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 : #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
215 : uint8_t req_slot_id;
216 : uint8_t mut_auth_requested;
217 : bool mandatory_mut_auth;
218 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
219 :
220 24 : spdm_request = request;
221 :
222 : /* -=[Check Parameters Phase]=- */
223 24 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_KEY_EXCHANGE);
224 :
225 24 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
226 0 : return libspdm_generate_error_response(spdm_context,
227 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
228 : SPDM_KEY_EXCHANGE,
229 : response_size, response);
230 : }
231 :
232 24 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
233 0 : return libspdm_generate_error_response(spdm_context,
234 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
235 : response_size, response);
236 : }
237 24 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
238 3 : return libspdm_responder_handle_response_state(
239 : spdm_context,
240 3 : spdm_request->header.request_response_code,
241 : response_size, response);
242 : }
243 21 : if (!libspdm_is_capabilities_flag_supported(
244 : spdm_context, false,
245 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP,
246 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP)) {
247 0 : return libspdm_generate_error_response(
248 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
249 : SPDM_KEY_EXCHANGE, response_size, response);
250 : }
251 :
252 : /* While clearing MAC_CAP and setting ENCRYPT_CAP is legal according to DSP0274, libspdm
253 : * also implements DSP0277 secure messages, which requires at least MAC_CAP to be set.
254 : */
255 21 : if (!libspdm_is_capabilities_flag_supported(
256 : spdm_context, false,
257 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP,
258 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP)) {
259 0 : return libspdm_generate_error_response(
260 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
261 : SPDM_KEY_EXCHANGE, response_size, response);
262 : }
263 :
264 21 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
265 1 : return libspdm_generate_error_response(spdm_context,
266 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
267 : 0, response_size, response);
268 : }
269 20 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
270 7 : if ((spdm_context->connection_info.algorithm.other_params_support &
271 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) != SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
272 0 : return libspdm_generate_error_response(
273 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
274 : 0, response_size, response);
275 : }
276 : }
277 20 : if (spdm_context->last_spdm_request_session_id_valid) {
278 0 : return libspdm_generate_error_response(spdm_context,
279 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
280 : 0, response_size, response);
281 : }
282 :
283 20 : if (spdm_request->header.param1 > 0) {
284 4 : if (!libspdm_is_capabilities_flag_supported(
285 : spdm_context, false,
286 3 : 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) ||
287 3 : (spdm_context->connection_info.algorithm.measurement_spec == 0) ||
288 3 : (spdm_context->connection_info.algorithm.measurement_hash_algo == 0) ) {
289 1 : return libspdm_generate_error_response(
290 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
291 : 0, response_size, response);
292 : }
293 : }
294 :
295 19 : slot_id = spdm_request->header.param2;
296 :
297 19 : if (libspdm_is_capabilities_flag_supported(
298 : spdm_context, false,
299 : 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
300 17 : if (slot_id >= SPDM_MAX_SLOT_COUNT) {
301 1 : return libspdm_generate_error_response(spdm_context,
302 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
303 : response_size, response);
304 : }
305 16 : if (spdm_context->local_context.local_cert_chain_provision[slot_id] == NULL) {
306 0 : return libspdm_generate_error_response(spdm_context,
307 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
308 : response_size, response);
309 : }
310 : } else {
311 2 : if (slot_id != 0xff) {
312 1 : return libspdm_generate_error_response(spdm_context,
313 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
314 : response_size, response);
315 : }
316 1 : if (spdm_context->local_context.local_public_key_provision == NULL) {
317 0 : return libspdm_generate_error_response(spdm_context,
318 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
319 : response_size, response);
320 : }
321 : }
322 :
323 17 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
324 3 : if (spdm_context->connection_info.multi_key_conn_rsp && (slot_id != 0xff)) {
325 1 : if ((spdm_context->local_context.local_key_usage_bit_mask[slot_id] &
326 : SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE) == 0) {
327 1 : return libspdm_generate_error_response(
328 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
329 : }
330 : }
331 :
332 2 : if ((spdm_request->session_policy &
333 : SPDM_KEY_EXCHANGE_REQUEST_SESSION_POLICY_EVENT_ALL_POLICY) != 0) {
334 2 : if (!libspdm_is_capabilities_flag_supported(
335 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP)) {
336 0 : return libspdm_generate_error_response(spdm_context,
337 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
338 : response_size, response);
339 : }
340 : }
341 : }
342 :
343 16 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
344 0 : signature_size = libspdm_get_pqc_asym_signature_size(
345 : spdm_context->connection_info.algorithm.pqc_asym_algo);
346 : } else {
347 16 : signature_size = libspdm_get_asym_signature_size(
348 : spdm_context->connection_info.algorithm.base_asym_algo);
349 : }
350 16 : hmac_size = libspdm_get_hash_size(
351 : spdm_context->connection_info.algorithm.base_hash_algo);
352 16 : if (spdm_context->connection_info.algorithm.kem_alg != 0) {
353 0 : kem_encap_key_size = libspdm_get_kem_encap_key_size(
354 : spdm_context->connection_info.algorithm.kem_alg);
355 0 : kem_cipher_text_size = libspdm_get_kem_cipher_text_size(
356 : spdm_context->connection_info.algorithm.kem_alg);
357 0 : req_key_exchange_size = kem_encap_key_size;
358 0 : rsp_key_exchange_size = kem_cipher_text_size;
359 : } else {
360 32 : dhe_key_size = libspdm_get_dhe_pub_key_size(
361 16 : spdm_context->connection_info.algorithm.dhe_named_group);
362 16 : req_key_exchange_size = dhe_key_size;
363 16 : rsp_key_exchange_size = dhe_key_size;
364 : }
365 16 : measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
366 16 : spdm_context, false, spdm_request->header.param1);
367 :
368 16 : if ((measurement_summary_hash_size == 0) &&
369 14 : (spdm_request->header.param1 != SPDM_KEY_EXCHANGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH)) {
370 1 : return libspdm_generate_error_response(spdm_context,
371 : SPDM_ERROR_CODE_INVALID_REQUEST,
372 : 0, response_size, response);
373 : }
374 15 : if (request_size < sizeof(spdm_key_exchange_request_t) + req_key_exchange_size +
375 : sizeof(uint16_t)) {
376 1 : return libspdm_generate_error_response(spdm_context,
377 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
378 : response_size, response);
379 : }
380 14 : opaque_data_length = libspdm_read_uint16((const uint8_t *)request +
381 14 : sizeof(spdm_key_exchange_request_t) +
382 : req_key_exchange_size);
383 14 : if (request_size < sizeof(spdm_key_exchange_request_t) + req_key_exchange_size +
384 14 : sizeof(uint16_t) + opaque_data_length) {
385 0 : return libspdm_generate_error_response(spdm_context,
386 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
387 : response_size, response);
388 : }
389 14 : request_size = sizeof(spdm_key_exchange_request_t) + req_key_exchange_size +
390 14 : sizeof(uint16_t) + opaque_data_length;
391 :
392 14 : if (opaque_data_length != 0) {
393 14 : req_opaque_data = (const uint8_t *)request + sizeof(spdm_key_exchange_request_t) +
394 14 : req_key_exchange_size + sizeof(uint16_t);
395 :
396 : /*
397 : * Here allows integrator generate own opaque data for Key Exchange Response.
398 : * If libspdm_key_exchange_rsp_opaque_data() returns false,
399 : * libspdm will generate version selection opaque data.
400 : */
401 14 : opaque_key_exchange_rsp_size = *response_size - sizeof(spdm_key_exchange_response_t) -
402 14 : rsp_key_exchange_size - measurement_summary_hash_size -
403 14 : sizeof(uint16_t) - signature_size - hmac_size;
404 :
405 14 : use_default_opaque_data = false;
406 14 : result = libspdm_key_exchange_rsp_opaque_data(
407 14 : spdm_context, spdm_request->header.spdm_version,
408 14 : spdm_request->header.param1, slot_id, spdm_request->session_policy,
409 : req_opaque_data, opaque_data_length, NULL,
410 : &opaque_key_exchange_rsp_size);
411 14 : if (!result) {
412 13 : use_default_opaque_data = true;
413 13 : opaque_key_exchange_rsp_size =
414 13 : libspdm_get_opaque_data_version_selection_data_size(spdm_context);
415 : }
416 :
417 14 : if (use_default_opaque_data) {
418 13 : result = libspdm_process_general_opaque_data_check(spdm_context, opaque_data_length,
419 : req_opaque_data);
420 13 : if (!result) {
421 0 : return libspdm_generate_error_response(spdm_context,
422 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
423 : response_size, response);
424 : }
425 13 : status = libspdm_process_opaque_data_supported_version_data(
426 : spdm_context, opaque_data_length, req_opaque_data, &secured_message_version);
427 13 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
428 0 : return libspdm_generate_error_response(spdm_context,
429 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
430 : response_size, response);
431 : }
432 : } else {
433 : /* use response buffer to temporarily store opaque data */
434 1 : rsp_opaque_data = (uint8_t *)response;
435 1 : result = libspdm_key_exchange_rsp_opaque_data(
436 1 : spdm_context, spdm_request->header.spdm_version,
437 1 : spdm_request->header.param1, slot_id, spdm_request->session_policy,
438 : req_opaque_data, opaque_data_length, rsp_opaque_data,
439 : &opaque_key_exchange_rsp_size);
440 1 : if (!result) {
441 0 : return libspdm_generate_error_response(spdm_context,
442 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
443 : response_size, response);
444 : }
445 : /*
446 : * parse responder opaque data from integrator
447 : * to get secured_message_version.
448 : */
449 1 : status = libspdm_process_opaque_data_version_selection_data(
450 : spdm_context, opaque_key_exchange_rsp_size,
451 : rsp_opaque_data, &secured_message_version);
452 1 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
453 0 : return libspdm_generate_error_response(spdm_context,
454 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
455 : response_size, response);
456 : }
457 : }
458 : } else {
459 0 : secured_message_version = 0;
460 0 : opaque_key_exchange_rsp_size = 0;
461 0 : req_opaque_data = NULL;
462 : }
463 :
464 14 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
465 14 : spdm_request->header.request_response_code);
466 :
467 14 : if (libspdm_is_capabilities_flag_supported(
468 : spdm_context, false,
469 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
470 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
471 3 : hmac_size = 0;
472 : }
473 :
474 14 : req_session_id = spdm_request->req_session_id;
475 14 : rsp_session_id = libspdm_allocate_rsp_session_id(spdm_context, false);
476 14 : if (rsp_session_id == ((INVALID_SESSION_ID & 0xFFFF0000) >> 16)) {
477 0 : return libspdm_generate_error_response(
478 : spdm_context, SPDM_ERROR_CODE_SESSION_LIMIT_EXCEEDED, 0,
479 : response_size, response);
480 : }
481 14 : session_id = libspdm_generate_session_id(req_session_id, rsp_session_id);
482 14 : session_info = libspdm_assign_session_id(spdm_context, session_id, secured_message_version,
483 : false);
484 14 : if (session_info == NULL) {
485 0 : return libspdm_generate_error_response(
486 : spdm_context, SPDM_ERROR_CODE_SESSION_LIMIT_EXCEEDED, 0,
487 : response_size, response);
488 : }
489 :
490 14 : total_size = sizeof(spdm_key_exchange_response_t) + rsp_key_exchange_size +
491 14 : measurement_summary_hash_size + sizeof(uint16_t) +
492 14 : opaque_key_exchange_rsp_size + signature_size + hmac_size;
493 :
494 14 : LIBSPDM_ASSERT(*response_size >= total_size);
495 14 : *response_size = total_size;
496 14 : libspdm_zero_mem(response, *response_size);
497 14 : spdm_response = response;
498 :
499 14 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
500 14 : spdm_response->header.request_response_code = SPDM_KEY_EXCHANGE_RSP;
501 :
502 14 : if (libspdm_is_capabilities_flag_supported(
503 : spdm_context, false,
504 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
505 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
506 0 : spdm_response->header.param1 = spdm_context->local_context.heartbeat_period;
507 : } else {
508 14 : spdm_response->header.param1 = 0x00;
509 : }
510 :
511 14 : session_info->local_used_cert_chain_slot_id = slot_id;
512 :
513 14 : if (libspdm_is_capabilities_flag_supported(
514 : spdm_context, false,
515 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
516 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
517 0 : session_info->heartbeat_period = spdm_context->local_context.heartbeat_period;
518 : } else {
519 14 : session_info->heartbeat_period = 0x00;
520 : }
521 :
522 14 : spdm_response->rsp_session_id = rsp_session_id;
523 14 : spdm_response->mut_auth_requested = 0;
524 14 : spdm_response->req_slot_id_param = 0;
525 :
526 : #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
527 14 : if (libspdm_is_capabilities_flag_supported(
528 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP)) {
529 3 : req_slot_id = 0;
530 :
531 : mut_auth_requested =
532 3 : libspdm_key_exchange_start_mut_auth(spdm_context,
533 : session_id,
534 3 : spdm_context->connection_info.version,
535 : slot_id,
536 : &req_slot_id,
537 3 : spdm_request->session_policy,
538 : opaque_data_length,
539 : req_opaque_data,
540 : &mandatory_mut_auth);
541 3 : if (mut_auth_requested != 0) {
542 2 : const bool req_mut_auth_cap = libspdm_is_capabilities_flag_supported(
543 : spdm_context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP, 0);
544 2 : const bool req_encap_cap = libspdm_is_capabilities_flag_supported(
545 : spdm_context, false, SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCAP_CAP, 0);
546 2 : const bool need_encap =
547 : (mut_auth_requested ==
548 2 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST) ||
549 : (mut_auth_requested ==
550 : SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS);
551 :
552 : /* If Integrator requires mutual authentication but Requester does not support mutual
553 : * authentication, or Integrator requires the encapsulated mutual authentication flow
554 : * and Requester does not support encapsulated messages, then return an error to
555 : * Requester. */
556 2 : if (mandatory_mut_auth && (!req_mut_auth_cap || (need_encap && !req_encap_cap))) {
557 2 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_13) {
558 1 : libspdm_free_session_id(spdm_context, session_id);
559 1 : return libspdm_generate_error_response(spdm_context,
560 : SPDM_ERROR_CODE_INVALID_POLICY, 0,
561 : response_size, response);
562 : } else {
563 1 : libspdm_free_session_id(spdm_context, session_id);
564 1 : return libspdm_generate_error_response(spdm_context,
565 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
566 : response_size, response);
567 : }
568 : }
569 :
570 0 : if (!need_encap) {
571 0 : spdm_response->mut_auth_requested = mut_auth_requested;
572 0 : spdm_response->req_slot_id_param = req_slot_id;
573 0 : } else if (need_encap && req_encap_cap) {
574 0 : spdm_response->mut_auth_requested = mut_auth_requested;
575 0 : session_info->peer_used_cert_chain_slot_id = req_slot_id;
576 0 : libspdm_init_mut_auth_encap_state(spdm_context, mut_auth_requested);
577 : }
578 : }
579 : }
580 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
581 :
582 12 : if (!libspdm_get_random_number(SPDM_RANDOM_DATA_SIZE, spdm_response->random_data)) {
583 0 : libspdm_free_session_id(spdm_context, session_id);
584 0 : return libspdm_generate_error_response(spdm_context,
585 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
586 : response_size, response);
587 : }
588 :
589 12 : ptr = (void *)(spdm_response + 1);
590 12 : if (spdm_context->connection_info.algorithm.kem_alg != 0) {
591 0 : kem_context = libspdm_secured_message_kem_new(
592 0 : spdm_context->connection_info.version,
593 : spdm_context->connection_info.algorithm.kem_alg, false);
594 0 : if (kem_context == NULL) {
595 0 : libspdm_free_session_id(spdm_context, session_id);
596 0 : return libspdm_generate_error_response(spdm_context,
597 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
598 : response_size, response);
599 : }
600 :
601 0 : result = libspdm_secured_message_kem_encapsulate(
602 : spdm_context->connection_info.algorithm.kem_alg,
603 : kem_context,
604 : (const uint8_t *)request + sizeof(spdm_key_exchange_request_t),
605 : kem_encap_key_size, ptr, &kem_cipher_text_size, session_info->secured_message_context);
606 0 : libspdm_secured_message_kem_free(
607 : spdm_context->connection_info.algorithm.kem_alg,
608 : kem_context);
609 0 : if (!result) {
610 0 : libspdm_free_session_id(spdm_context, session_id);
611 0 : return libspdm_generate_error_response(spdm_context,
612 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
613 : response_size, response);
614 : }
615 :
616 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc Self cipher_text (0x%zx):\n", kem_cipher_text_size));
617 0 : LIBSPDM_INTERNAL_DUMP_HEX(ptr, kem_cipher_text_size);
618 :
619 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc peer encap_key (0x%zx):\n", kem_encap_key_size));
620 0 : LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)request +
621 : sizeof(spdm_key_exchange_request_t),
622 : kem_encap_key_size);
623 :
624 0 : ptr += kem_cipher_text_size;
625 : } else {
626 12 : dhe_context = libspdm_secured_message_dhe_new(
627 12 : spdm_context->connection_info.version,
628 12 : spdm_context->connection_info.algorithm.dhe_named_group, false);
629 12 : if (dhe_context == NULL) {
630 0 : libspdm_free_session_id(spdm_context, session_id);
631 0 : return libspdm_generate_error_response(spdm_context,
632 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
633 : response_size, response);
634 : }
635 :
636 12 : result = libspdm_secured_message_dhe_generate_key(
637 12 : spdm_context->connection_info.algorithm.dhe_named_group,
638 : dhe_context, ptr, &dhe_key_size);
639 12 : if (!result) {
640 0 : libspdm_secured_message_dhe_free(
641 0 : spdm_context->connection_info.algorithm.dhe_named_group,
642 : dhe_context);
643 0 : libspdm_free_session_id(spdm_context, session_id);
644 0 : return libspdm_generate_error_response(spdm_context,
645 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
646 : response_size, response);
647 : }
648 :
649 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc SelfKey (0x%zx):\n", dhe_key_size));
650 12 : LIBSPDM_INTERNAL_DUMP_HEX(ptr, dhe_key_size);
651 :
652 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc peer_key (0x%zx):\n", dhe_key_size));
653 12 : LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)request +
654 : sizeof(spdm_key_exchange_request_t),
655 : dhe_key_size);
656 :
657 12 : result = libspdm_secured_message_dhe_compute_key(
658 12 : spdm_context->connection_info.algorithm.dhe_named_group,
659 : dhe_context,
660 : (const uint8_t *)request + sizeof(spdm_key_exchange_request_t),
661 : dhe_key_size, session_info->secured_message_context);
662 12 : libspdm_secured_message_dhe_free(
663 12 : spdm_context->connection_info.algorithm.dhe_named_group, dhe_context);
664 12 : if (!result) {
665 0 : libspdm_free_session_id(spdm_context, session_id);
666 0 : return libspdm_generate_error_response(spdm_context,
667 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
668 : response_size, response);
669 : }
670 :
671 12 : ptr += dhe_key_size;
672 : }
673 :
674 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
675 12 : if (libspdm_is_capabilities_flag_supported(
676 2 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) &&
677 2 : ((spdm_request->header.param1 == SPDM_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH) ||
678 1 : (spdm_request->header.param1 == SPDM_REQUEST_ALL_MEASUREMENTS_HASH))) {
679 2 : result = libspdm_generate_measurement_summary_hash(
680 : spdm_context,
681 2 : spdm_context->connection_info.version,
682 : spdm_context->connection_info.algorithm.base_hash_algo,
683 2 : spdm_context->connection_info.algorithm.measurement_spec,
684 : spdm_context->connection_info.algorithm.measurement_hash_algo,
685 2 : spdm_request->header.param1,
686 : ptr,
687 : measurement_summary_hash_size);
688 :
689 2 : 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 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP */
697 :
698 12 : ptr += measurement_summary_hash_size;
699 :
700 12 : libspdm_write_uint16(ptr, (uint16_t)opaque_key_exchange_rsp_size);
701 12 : ptr += sizeof(uint16_t);
702 :
703 12 : if (opaque_key_exchange_rsp_size != 0) {
704 12 : if (use_default_opaque_data) {
705 11 : libspdm_build_opaque_data_version_selection_data(
706 : spdm_context, secured_message_version, &opaque_key_exchange_rsp_size, ptr);
707 : } else {
708 1 : result = libspdm_key_exchange_rsp_opaque_data(
709 1 : spdm_context, spdm_request->header.spdm_version,
710 1 : spdm_request->header.param1, slot_id, spdm_request->session_policy,
711 : req_opaque_data, opaque_data_length, ptr,
712 : &opaque_key_exchange_rsp_size);
713 1 : if (!result) {
714 0 : libspdm_free_session_id(spdm_context, session_id);
715 0 : return libspdm_generate_error_response(spdm_context,
716 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
717 : response_size, response);
718 : }
719 : }
720 12 : ptr += opaque_key_exchange_rsp_size;
721 : }
722 :
723 12 : status = libspdm_append_message_k(spdm_context, session_info, false, request, request_size);
724 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
725 0 : libspdm_free_session_id(spdm_context, session_id);
726 0 : return libspdm_generate_error_response(spdm_context,
727 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
728 : response_size, response);
729 : }
730 :
731 12 : status = libspdm_append_message_k(spdm_context, session_info, false, spdm_response,
732 12 : (size_t)ptr - (size_t)spdm_response);
733 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
734 0 : libspdm_free_session_id(spdm_context, session_id);
735 0 : return libspdm_generate_error_response(spdm_context,
736 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
737 : response_size, response);
738 : }
739 12 : result = libspdm_generate_key_exchange_rsp_signature(
740 : spdm_context, session_info, slot_id, ptr);
741 12 : if (!result) {
742 0 : libspdm_free_session_id(spdm_context, session_id);
743 0 : return libspdm_generate_error_response(
744 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
745 : 0, response_size, response);
746 : }
747 :
748 12 : status = libspdm_append_message_k(spdm_context, session_info, false, ptr, signature_size);
749 12 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
750 0 : libspdm_free_session_id(spdm_context, session_id);
751 0 : return libspdm_generate_error_response(spdm_context,
752 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
753 : response_size, response);
754 : }
755 :
756 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_handshake_key[%x]\n", session_id));
757 12 : result = libspdm_calculate_th1_hash(spdm_context, session_info, false, th1_hash_data);
758 12 : if (!result) {
759 0 : libspdm_free_session_id(spdm_context, session_id);
760 0 : return libspdm_generate_error_response(spdm_context,
761 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
762 : response_size, response);
763 : }
764 12 : result = libspdm_generate_session_handshake_key(
765 : session_info->secured_message_context, th1_hash_data);
766 12 : if (!result) {
767 0 : libspdm_free_session_id(spdm_context, session_id);
768 0 : return libspdm_generate_error_response(spdm_context,
769 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
770 : response_size, response);
771 : }
772 :
773 12 : ptr += signature_size;
774 :
775 12 : if (!libspdm_is_capabilities_flag_supported(
776 : spdm_context, false,
777 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP,
778 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP)) {
779 9 : result = libspdm_generate_key_exchange_rsp_hmac(spdm_context, session_info, ptr);
780 9 : if (!result) {
781 0 : libspdm_free_session_id(spdm_context, session_id);
782 0 : return libspdm_generate_error_response(
783 : spdm_context,
784 : SPDM_ERROR_CODE_UNSPECIFIED,
785 : 0, response_size, response);
786 : }
787 9 : status = libspdm_append_message_k(spdm_context, session_info, false, ptr, hmac_size);
788 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
789 0 : libspdm_free_session_id(spdm_context, session_id);
790 0 : return libspdm_generate_error_response(
791 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
792 : 0, response_size, response);
793 : }
794 :
795 9 : ptr += hmac_size;
796 : }
797 :
798 : #if LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP
799 12 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
800 1 : if ((spdm_request->session_policy &
801 : SPDM_KEY_EXCHANGE_REQUEST_SESSION_POLICY_EVENT_ALL_POLICY) != 0) {
802 1 : if (!libspdm_event_subscribe(spdm_context, spdm_context->connection_info.version,
803 : session_id, LIBSPDM_EVENT_SUBSCRIBE_ALL, 0, 0, NULL)) {
804 0 : libspdm_free_session_id(spdm_context, session_id);
805 0 : return libspdm_generate_error_response(spdm_context,
806 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
807 : response_size, response);
808 : }
809 : }
810 : }
811 : #endif /* LIBSPDM_ENABLE_CAPABILITY_EVENT_CAP */
812 :
813 12 : session_info->mut_auth_requested = spdm_response->mut_auth_requested;
814 12 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12) {
815 4 : session_info->session_policy = spdm_request->session_policy;
816 : }
817 12 : libspdm_set_session_state(spdm_context, session_id, LIBSPDM_SESSION_STATE_HANDSHAKING);
818 :
819 12 : return LIBSPDM_STATUS_SUCCESS;
820 : }
821 :
822 : #endif /* LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP */
|