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 "spdm_unit_test.h"
8 : #include "internal/libspdm_responder_lib.h"
9 :
10 : #if LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP
11 :
12 : #define CHUNK_GET_UNIT_TEST_OVERRIDE_DATA_TRANSFER_SIZE (64)
13 :
14 : typedef struct {
15 : spdm_message_header_t header;
16 : /* param1 == RSVD
17 : * param2 == RSVD*/
18 : uint16_t standard_id;
19 : uint8_t len;
20 : /*uint8_t vendor_id[len];*/
21 : uint16_t payload_length;
22 : /* uint8_t vendor_defined_payload[payload_length];*/
23 : } my_spdm_vendor_defined_request_msg_t;
24 :
25 :
26 1 : libspdm_return_t my_test_get_response_func(
27 : void *spdm_context, const uint32_t *session_id, bool is_app_message,
28 : size_t request_size, const void *request, size_t *response_size,
29 : void *response)
30 : {
31 : /* response message size is greater than the sending transmit buffer size of responder */
32 1 : *response_size = CHUNK_GET_UNIT_TEST_OVERRIDE_DATA_TRANSFER_SIZE + 1;
33 1 : return LIBSPDM_STATUS_SUCCESS;
34 : }
35 :
36 1 : libspdm_return_t my_test_get_response_func2(
37 : void *spdm_context,
38 : const uint32_t *session_id,
39 : uint16_t req_standard_id,
40 : uint8_t req_vendor_id_len,
41 : const void *req_vendor_id,
42 : uint32_t req_size,
43 : const void *req_data,
44 : uint32_t *resp_size,
45 : void *resp_data)
46 : {
47 : /* response message size is greater than the sending transmit buffer size of responder */
48 1 : *resp_size = CHUNK_GET_UNIT_TEST_OVERRIDE_DATA_TRANSFER_SIZE + 1;
49 1 : return LIBSPDM_STATUS_SUCCESS;
50 : }
51 :
52 : /**
53 : * Test 1: Test Responder Receive Send flow triggers chunk get mode
54 : * if response buffer is larger than requester data_transfer_size.
55 : **/
56 1 : static void libspdm_test_responder_receive_send_rsp_case1(void** state)
57 : {
58 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
59 : /* This test case is partially copied from test_requester_get_measurement_case4 */
60 : libspdm_return_t status;
61 : libspdm_test_context_t* spdm_test_context;
62 : libspdm_context_t* spdm_context;
63 : size_t response_size;
64 : uint8_t* response;
65 : spdm_error_response_t* spdm_response;
66 : spdm_get_measurements_request_t spdm_request;
67 : void* message;
68 : size_t message_size;
69 : void* data;
70 : size_t data_size;
71 : void* hash;
72 : size_t hash_size;
73 : uint32_t transport_header_size;
74 : uint8_t chunk_handle;
75 :
76 1 : spdm_test_context = *state;
77 1 : spdm_context = spdm_test_context->spdm_context;
78 1 : spdm_test_context->case_id = 1;
79 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
80 : SPDM_VERSION_NUMBER_SHIFT_BIT;
81 :
82 1 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AUTHENTICATED;
83 :
84 1 : spdm_context->local_context.capability.flags |=
85 : (SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP
86 : | SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
87 1 : spdm_context->connection_info.capability.flags |= SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
88 :
89 1 : if (!libspdm_read_responder_public_certificate_chain(
90 : m_libspdm_use_hash_algo,
91 : m_libspdm_use_asym_algo, &data,
92 : &data_size,
93 : &hash, &hash_size)) {
94 0 : return;
95 : }
96 :
97 1 : spdm_context->local_context.local_cert_chain_provision_size[0] = data_size;
98 1 : spdm_context->local_context.local_cert_chain_provision[0] = data;
99 :
100 1 : libspdm_reset_message_m(spdm_context, NULL);
101 :
102 1 : spdm_context->connection_info.algorithm.measurement_spec = m_libspdm_use_measurement_spec;
103 1 : spdm_context->connection_info.algorithm.measurement_hash_algo =
104 : m_libspdm_use_measurement_hash_algo;
105 1 : spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo;
106 1 : spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo;
107 :
108 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
109 : spdm_context->connection_info.peer_used_cert_chain[0].buffer_size = data_size;
110 : libspdm_copy_mem(
111 : spdm_context->connection_info.peer_used_cert_chain[0].buffer,
112 : sizeof(spdm_context->connection_info.peer_used_cert_chain[0].buffer),
113 : data, data_size);
114 : #else
115 1 : libspdm_hash_all(
116 : spdm_context->connection_info.algorithm.base_hash_algo,
117 : data, data_size,
118 1 : spdm_context->connection_info.peer_used_cert_chain[0].buffer_hash);
119 1 : spdm_context->connection_info.peer_used_cert_chain[0].buffer_hash_size =
120 1 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
121 1 : libspdm_get_leaf_cert_public_key_from_cert_chain(
122 : spdm_context->connection_info.algorithm.base_hash_algo,
123 : spdm_context->connection_info.algorithm.base_asym_algo,
124 : data, data_size,
125 : &spdm_context->connection_info.peer_used_cert_chain[0].leaf_cert_public_key);
126 : #endif
127 :
128 1 : spdm_context->connection_info.capability.data_transfer_size =
129 : CHUNK_GET_UNIT_TEST_OVERRIDE_DATA_TRANSFER_SIZE;
130 :
131 1 : spdm_context->connection_info.capability.max_spdm_msg_size = LIBSPDM_MAX_SPDM_MSG_SIZE;
132 :
133 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
134 1 : spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_12;
135 1 : spdm_request.header.request_response_code = SPDM_GET_MEASUREMENTS;
136 1 : spdm_request.header.param1 = SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE;
137 1 : spdm_request.header.param2 =
138 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS;
139 1 : spdm_request.slot_id_param = 0;
140 :
141 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
142 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
143 : &spdm_request, sizeof(spdm_request));
144 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
145 :
146 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, false);
147 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void**) &message);
148 1 : response = message;
149 1 : response_size = message_size;
150 1 : libspdm_zero_mem(response, response_size);
151 :
152 1 : status = libspdm_build_response(spdm_context, NULL, false, &response_size, (void**)&response);
153 :
154 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
155 1 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
156 :
157 : /* Verify responder returned error large response with chunk_handle == 1
158 : * and responder is in chunking mode (get.chunk_in_use). */
159 1 : spdm_response = (spdm_error_response_t*) ((uint8_t*)message + transport_header_size);
160 1 : assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12);
161 1 : assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
162 1 : assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_LARGE_RESPONSE);
163 1 : assert_int_equal(spdm_response->header.param2, 0);
164 :
165 1 : chunk_handle = *(uint8_t*)(spdm_response + 1);
166 1 : assert_int_equal(chunk_handle, spdm_context->chunk_context.get.chunk_handle);
167 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, true);
168 1 : assert_int_equal(spdm_context->chunk_context.get.large_message_capacity,
169 : spdm_context->local_context.capability.max_spdm_msg_size);
170 1 : libspdm_release_sender_buffer(spdm_context);
171 :
172 1 : free(data);
173 1 : libspdm_reset_message_m(spdm_context, NULL);
174 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
175 : #else
176 1 : libspdm_asym_free(spdm_context->connection_info.algorithm.base_asym_algo,
177 : spdm_context->connection_info.peer_used_cert_chain[0].leaf_cert_public_key);
178 : #endif
179 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP */
180 : }
181 :
182 : /**
183 : * Test 2: Test Responder Receive Send flow triggers chunk get mode
184 : * if response message size is larger than responder sending transmit buffer size.
185 : **/
186 1 : static void libspdm_test_responder_receive_send_rsp_case2(void** state)
187 : {
188 : libspdm_return_t status;
189 : libspdm_test_context_t* spdm_test_context;
190 : libspdm_context_t* spdm_context;
191 : size_t response_size;
192 : uint8_t* response;
193 : spdm_error_response_t* spdm_response;
194 : my_spdm_vendor_defined_request_msg_t spdm_request;
195 : void* message;
196 : size_t message_size;
197 : uint32_t transport_header_size;
198 : uint8_t chunk_handle;
199 :
200 1 : spdm_test_context = *state;
201 1 : spdm_context = spdm_test_context->spdm_context;
202 1 : spdm_test_context->case_id = 2;
203 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
204 : SPDM_VERSION_NUMBER_SHIFT_BIT;
205 :
206 1 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AUTHENTICATED;
207 :
208 1 : spdm_context->local_context.capability.flags |=
209 : (SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP
210 : | SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
211 1 : spdm_context->connection_info.capability.flags |= SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
212 :
213 : /* The local Responder transmit buffer size for sending a single and complete SPDM message */
214 1 : spdm_context->local_context.capability.sender_data_transfer_size =
215 : CHUNK_GET_UNIT_TEST_OVERRIDE_DATA_TRANSFER_SIZE;
216 : /* The peer Requester buffer size for receiving a single and complete SPDM message */
217 1 : spdm_context->connection_info.capability.data_transfer_size = LIBSPDM_DATA_TRANSFER_SIZE;
218 :
219 1 : spdm_context->connection_info.capability.max_spdm_msg_size = LIBSPDM_MAX_SPDM_MSG_SIZE;
220 :
221 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
222 1 : spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_12;
223 1 : spdm_request.header.request_response_code = SPDM_VENDOR_DEFINED_REQUEST;
224 :
225 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
226 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
227 : &spdm_request, sizeof(spdm_request));
228 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
229 :
230 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, false);
231 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void**) &message);
232 :
233 1 : response = message;
234 1 : response_size = message_size;
235 1 : libspdm_zero_mem(response, response_size);
236 :
237 : /* Make response message size greater than the sending transmit buffer size of responder */
238 1 : spdm_context->get_response_func = (void *)my_test_get_response_func;
239 :
240 1 : status = libspdm_build_response(spdm_context, NULL, false, &response_size, (void**)&response);
241 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
242 1 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
243 :
244 : /* Verify responder returned error large response with chunk_handle == 1
245 : * and responder is in chunking mode (get.chunk_in_use). */
246 1 : spdm_response = (spdm_error_response_t*) ((uint8_t*)message + transport_header_size);
247 1 : assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12);
248 1 : assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
249 1 : assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_LARGE_RESPONSE);
250 1 : assert_int_equal(spdm_response->header.param2, 0);
251 :
252 1 : chunk_handle = *(uint8_t*)(spdm_response + 1);
253 1 : assert_int_equal(chunk_handle, spdm_context->chunk_context.get.chunk_handle);
254 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, true);
255 1 : assert_int_equal(spdm_context->chunk_context.get.large_message_capacity,
256 : spdm_context->local_context.capability.max_spdm_msg_size);
257 1 : libspdm_release_sender_buffer(spdm_context);
258 1 : }
259 :
260 :
261 : #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
262 : /**
263 : * Test 3: Test Responder Receive Send flow triggers chunk get mode
264 : * if response message size is larger than responder sending transmit buffer size.
265 : **/
266 1 : static void libspdm_test_responder_receive_send_rsp_case3(void** state)
267 : {
268 : libspdm_return_t status;
269 : libspdm_test_context_t* spdm_test_context;
270 : libspdm_context_t* spdm_context;
271 : size_t response_size;
272 : uint8_t* response;
273 : spdm_error_response_t* spdm_response;
274 : my_spdm_vendor_defined_request_msg_t spdm_request;
275 : void* message;
276 : size_t message_size;
277 : uint32_t transport_header_size;
278 : uint8_t chunk_handle;
279 :
280 1 : spdm_test_context = *state;
281 1 : spdm_context = spdm_test_context->spdm_context;
282 1 : spdm_test_context->case_id = 2;
283 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
284 : SPDM_VERSION_NUMBER_SHIFT_BIT;
285 :
286 1 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AUTHENTICATED;
287 :
288 1 : spdm_context->local_context.capability.flags |=
289 : (SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP
290 : | SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
291 1 : spdm_context->connection_info.capability.flags |= SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
292 :
293 : /* The local Responder transmit buffer size for sending a single and complete SPDM message */
294 1 : spdm_context->local_context.capability.sender_data_transfer_size =
295 : CHUNK_GET_UNIT_TEST_OVERRIDE_DATA_TRANSFER_SIZE;
296 : /* The peer Requester buffer size for receiving a single and complete SPDM message */
297 1 : spdm_context->connection_info.capability.data_transfer_size = LIBSPDM_DATA_TRANSFER_SIZE;
298 :
299 1 : spdm_context->connection_info.capability.max_spdm_msg_size = LIBSPDM_MAX_SPDM_MSG_SIZE;
300 :
301 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
302 1 : spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_12;
303 1 : spdm_request.header.request_response_code = SPDM_VENDOR_DEFINED_REQUEST;
304 :
305 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
306 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
307 : &spdm_request, sizeof(spdm_request));
308 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
309 :
310 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, false);
311 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void**) &message);
312 :
313 1 : response = message;
314 1 : response_size = message_size;
315 1 : libspdm_zero_mem(response, response_size);
316 :
317 : /* Make response message size greater than the sending transmit buffer size of responder */
318 1 : libspdm_register_vendor_callback_func(spdm_context, my_test_get_response_func2);
319 :
320 1 : status = libspdm_build_response(spdm_context, NULL, false, &response_size, (void**)&response);
321 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
322 1 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
323 :
324 : /* Verify responder returned error large response with chunk_handle == 1
325 : * and responder is in chunking mode (get.chunk_in_use). */
326 1 : spdm_response = (spdm_error_response_t*) ((uint8_t*)message + transport_header_size);
327 1 : assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12);
328 1 : assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
329 1 : assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_LARGE_RESPONSE);
330 1 : assert_int_equal(spdm_response->header.param2, 0);
331 :
332 1 : chunk_handle = *(uint8_t*)(spdm_response + 1);
333 1 : assert_int_equal(chunk_handle, spdm_context->chunk_context.get.chunk_handle);
334 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, true);
335 1 : assert_int_equal(spdm_context->chunk_context.get.large_message_capacity,
336 : spdm_context->local_context.capability.max_spdm_msg_size);
337 1 : libspdm_release_sender_buffer(spdm_context);
338 1 : }
339 : #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
340 :
341 : /**
342 : * Test 4: Test Responder Receive Send flow triggers chunk get mode
343 : * if response buffer is larger than requester max_spdm_msg_size.
344 : * expect: SPDM_ERROR_CODE_RESPONSE_TOO_LARGE
345 : **/
346 1 : static void libspdm_test_responder_receive_send_rsp_case4(void** state)
347 : {
348 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
349 : /* This test case is partially copied from test_requester_get_measurement_case4 */
350 : libspdm_return_t status;
351 : libspdm_test_context_t* spdm_test_context;
352 : libspdm_context_t* spdm_context;
353 : size_t response_size;
354 : uint8_t* response;
355 : spdm_error_response_t* spdm_response;
356 : spdm_get_measurements_request_t spdm_request;
357 : void* message;
358 : size_t message_size;
359 : void* data;
360 : size_t data_size;
361 : void* hash;
362 : size_t hash_size;
363 : uint32_t transport_header_size;
364 :
365 1 : spdm_test_context = *state;
366 1 : spdm_context = spdm_test_context->spdm_context;
367 1 : spdm_test_context->case_id = 3;
368 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
369 : SPDM_VERSION_NUMBER_SHIFT_BIT;
370 :
371 1 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AUTHENTICATED;
372 :
373 1 : spdm_context->local_context.capability.flags |=
374 : (SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP
375 : | SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP);
376 1 : spdm_context->connection_info.capability.flags |= SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
377 :
378 1 : if (!libspdm_read_responder_public_certificate_chain(
379 : m_libspdm_use_hash_algo,
380 : m_libspdm_use_asym_algo, &data,
381 : &data_size,
382 : &hash, &hash_size)) {
383 0 : return;
384 : }
385 :
386 1 : spdm_context->local_context.local_cert_chain_provision_size[0] = data_size;
387 1 : spdm_context->local_context.local_cert_chain_provision[0] = data;
388 :
389 1 : libspdm_reset_message_m(spdm_context, NULL);
390 :
391 1 : spdm_context->connection_info.algorithm.measurement_spec = m_libspdm_use_measurement_spec;
392 1 : spdm_context->connection_info.algorithm.measurement_hash_algo =
393 : m_libspdm_use_measurement_hash_algo;
394 1 : spdm_context->connection_info.algorithm.base_hash_algo = m_libspdm_use_hash_algo;
395 1 : spdm_context->connection_info.algorithm.base_asym_algo = m_libspdm_use_asym_algo;
396 :
397 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
398 : spdm_context->connection_info.peer_used_cert_chain[0].buffer_size = data_size;
399 : libspdm_copy_mem(
400 : spdm_context->connection_info.peer_used_cert_chain[0].buffer,
401 : sizeof(spdm_context->connection_info.peer_used_cert_chain[0].buffer),
402 : data, data_size);
403 : #else
404 1 : libspdm_hash_all(
405 : spdm_context->connection_info.algorithm.base_hash_algo,
406 : data, data_size,
407 1 : spdm_context->connection_info.peer_used_cert_chain[0].buffer_hash);
408 1 : spdm_context->connection_info.peer_used_cert_chain[0].buffer_hash_size =
409 1 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
410 1 : libspdm_get_leaf_cert_public_key_from_cert_chain(
411 : spdm_context->connection_info.algorithm.base_hash_algo,
412 : spdm_context->connection_info.algorithm.base_asym_algo,
413 : data, data_size,
414 : &spdm_context->connection_info.peer_used_cert_chain[0].leaf_cert_public_key);
415 : #endif
416 :
417 1 : spdm_context->connection_info.capability.data_transfer_size =
418 : CHUNK_GET_UNIT_TEST_OVERRIDE_DATA_TRANSFER_SIZE;
419 :
420 : /*set requester small max_spdm_msg_size*/
421 1 : spdm_context->connection_info.capability.max_spdm_msg_size = 100;
422 :
423 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
424 1 : spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_12;
425 1 : spdm_request.header.request_response_code = SPDM_GET_MEASUREMENTS;
426 1 : spdm_request.header.param1 = SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_GENERATE_SIGNATURE;
427 1 : spdm_request.header.param2 =
428 : SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS;
429 1 : spdm_request.slot_id_param = 0;
430 :
431 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
432 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
433 : &spdm_request, sizeof(spdm_request));
434 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
435 :
436 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, false);
437 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void**) &message);
438 1 : response = message;
439 1 : response_size = message_size;
440 1 : libspdm_zero_mem(response, response_size);
441 :
442 1 : status = libspdm_build_response(spdm_context, NULL, false, &response_size, (void**)&response);
443 :
444 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
445 1 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
446 :
447 : /* Verify responder returned SPDM_ERROR_CODE_RESPONSE_TOO_LARGE response with chunk_handle == 0
448 : * and responder is not in chunking mode (get.chunk_in_use). */
449 1 : spdm_response = (spdm_error_response_t*) ((uint8_t*)message + transport_header_size);
450 1 : assert_int_equal(spdm_response->header.spdm_version, SPDM_MESSAGE_VERSION_12);
451 1 : assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
452 :
453 1 : assert_int_equal(spdm_response->header.param1, SPDM_ERROR_CODE_RESPONSE_TOO_LARGE);
454 1 : assert_int_equal(spdm_response->header.param2, 0);
455 1 : assert_int_equal(0, spdm_context->chunk_context.get.chunk_handle);
456 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_in_use, false);
457 1 : libspdm_release_sender_buffer(spdm_context);
458 :
459 1 : free(data);
460 1 : libspdm_reset_message_m(spdm_context, NULL);
461 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
462 : #else
463 1 : libspdm_asym_free(spdm_context->connection_info.algorithm.base_asym_algo,
464 : spdm_context->connection_info.peer_used_cert_chain[0].leaf_cert_public_key);
465 : #endif
466 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP */
467 : }
468 :
469 : /**
470 : * Test 5: During an active chunk GET transfer, a non-chunk, non-GET_VERSION
471 : * request should be rejected with UnexpectedRequest error, and
472 : * the chunk transfer sequence should NOT be terminated.
473 : **/
474 1 : static void libspdm_test_responder_receive_send_rsp_case5(void** state)
475 : {
476 : libspdm_return_t status;
477 : libspdm_test_context_t *spdm_test_context;
478 : libspdm_context_t *spdm_context;
479 : size_t response_size;
480 : uint8_t *response;
481 : spdm_error_response_t *spdm_response;
482 : spdm_message_header_t spdm_request;
483 : void *message;
484 : size_t message_size;
485 : uint32_t transport_header_size;
486 : uint8_t saved_chunk_handle;
487 :
488 1 : spdm_test_context = *state;
489 1 : spdm_context = spdm_test_context->spdm_context;
490 1 : spdm_test_context->case_id = 5;
491 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
492 : SPDM_VERSION_NUMBER_SHIFT_BIT;
493 1 : spdm_context->connection_info.connection_state =
494 : LIBSPDM_CONNECTION_STATE_NEGOTIATED;
495 1 : spdm_context->local_context.capability.flags |=
496 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP;
497 1 : spdm_context->connection_info.capability.flags |=
498 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
499 1 : spdm_context->connection_info.capability.data_transfer_size =
500 : LIBSPDM_DATA_TRANSFER_SIZE;
501 1 : spdm_context->connection_info.capability.max_spdm_msg_size =
502 : LIBSPDM_MAX_SPDM_MSG_SIZE;
503 :
504 : /* Simulate an active chunk GET transfer. */
505 1 : spdm_context->chunk_context.get.chunk_in_use = true;
506 1 : spdm_context->chunk_context.get.chunk_handle = 1;
507 1 : spdm_context->chunk_context.get.chunk_seq_no = 2;
508 1 : saved_chunk_handle = spdm_context->chunk_context.get.chunk_handle;
509 :
510 : /* Send a GET_CAPABILITIES request (non-chunk, non-GET_VERSION). */
511 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
512 1 : spdm_request.spdm_version = SPDM_MESSAGE_VERSION_12;
513 1 : spdm_request.request_response_code = SPDM_GET_CAPABILITIES;
514 :
515 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
516 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
517 : &spdm_request, sizeof(spdm_request));
518 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
519 :
520 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void **)&message);
521 1 : response = message;
522 1 : response_size = message_size;
523 1 : libspdm_zero_mem(response, response_size);
524 :
525 1 : status = libspdm_build_response(spdm_context, NULL, false,
526 : &response_size, (void **)&response);
527 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
528 :
529 1 : transport_header_size =
530 : spdm_context->local_context.capability.transport_header_size;
531 1 : spdm_response = (spdm_error_response_t *)((uint8_t *)message + transport_header_size);
532 :
533 : /* Verify error UnexpectedRequest is returned. */
534 1 : assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
535 1 : assert_int_equal(spdm_response->header.param1,
536 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST);
537 :
538 : /* Verify chunk transfer sequence is NOT terminated. */
539 1 : assert_true(spdm_context->chunk_context.get.chunk_in_use);
540 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_handle,
541 : saved_chunk_handle);
542 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_seq_no, 2);
543 :
544 1 : libspdm_release_sender_buffer(spdm_context);
545 :
546 : /* Clean up chunk state for subsequent tests. */
547 1 : spdm_context->chunk_context.get.chunk_in_use = false;
548 1 : }
549 :
550 : /**
551 : * Test 6: During an active chunk GET transfer, a GET_VERSION request
552 : * should be allowed to interrupt: the chunk transfer should be
553 : * terminated and GET_VERSION processed normally.
554 : **/
555 1 : static void libspdm_test_responder_receive_send_rsp_case6(void** state)
556 : {
557 : libspdm_return_t status;
558 : libspdm_test_context_t *spdm_test_context;
559 : libspdm_context_t *spdm_context;
560 : size_t response_size;
561 : uint8_t *response;
562 : spdm_message_header_t *spdm_response;
563 : spdm_get_version_request_t spdm_request;
564 : void *message;
565 : size_t message_size;
566 : uint32_t transport_header_size;
567 : void *scratch_buffer;
568 : size_t scratch_buffer_size;
569 : uint8_t *large_message;
570 : size_t large_message_capacity;
571 : size_t i;
572 :
573 1 : spdm_test_context = *state;
574 1 : spdm_context = spdm_test_context->spdm_context;
575 1 : spdm_test_context->case_id = 6;
576 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
577 : SPDM_VERSION_NUMBER_SHIFT_BIT;
578 1 : spdm_context->connection_info.connection_state =
579 : LIBSPDM_CONNECTION_STATE_NEGOTIATED;
580 1 : spdm_context->local_context.capability.flags |=
581 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP;
582 1 : spdm_context->connection_info.capability.flags |=
583 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
584 1 : spdm_context->connection_info.capability.data_transfer_size =
585 : LIBSPDM_DATA_TRANSFER_SIZE;
586 1 : spdm_context->connection_info.capability.max_spdm_msg_size =
587 : LIBSPDM_MAX_SPDM_MSG_SIZE;
588 :
589 : /* Simulate an active chunk GET transfer. */
590 1 : libspdm_get_scratch_buffer(spdm_context, &scratch_buffer, &scratch_buffer_size);
591 2 : large_message = (uint8_t *)scratch_buffer +
592 1 : libspdm_get_scratch_buffer_large_message_offset(spdm_context);
593 1 : large_message_capacity = libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
594 1 : libspdm_set_mem(large_message, large_message_capacity, 0xa5);
595 :
596 1 : spdm_context->chunk_context.get.chunk_in_use = true;
597 1 : spdm_context->chunk_context.get.chunk_handle = 1;
598 1 : spdm_context->chunk_context.get.chunk_seq_no = 2;
599 1 : spdm_context->chunk_context.get.large_message = large_message;
600 1 : spdm_context->chunk_context.get.large_message_size = large_message_capacity;
601 1 : spdm_context->chunk_context.get.large_message_capacity = large_message_capacity;
602 :
603 : /* Send a GET_VERSION request. */
604 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
605 1 : spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_10;
606 1 : spdm_request.header.request_response_code = SPDM_GET_VERSION;
607 :
608 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
609 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
610 : &spdm_request, sizeof(spdm_request));
611 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
612 :
613 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void **)&message);
614 1 : response = message;
615 1 : response_size = message_size;
616 1 : libspdm_zero_mem(response, response_size);
617 :
618 1 : status = libspdm_build_response(spdm_context, NULL, false,
619 : &response_size, (void **)&response);
620 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
621 :
622 1 : transport_header_size =
623 : spdm_context->local_context.capability.transport_header_size;
624 1 : spdm_response = (spdm_message_header_t *)((uint8_t *)message + transport_header_size);
625 :
626 : /* Verify GET_VERSION was processed: response should be VERSION. */
627 1 : assert_int_equal(spdm_response->request_response_code, SPDM_VERSION);
628 :
629 : /* Verify chunk transfer was terminated. */
630 1 : assert_false(spdm_context->chunk_context.get.chunk_in_use);
631 1 : assert_int_equal(spdm_context->chunk_context.get.chunk_seq_no, 0);
632 :
633 1 : assert_null(spdm_context->chunk_context.get.large_message);
634 1 : assert_int_equal(spdm_context->chunk_context.get.large_message_size, 0);
635 1 : assert_int_equal(spdm_context->chunk_context.get.large_message_capacity, 0);
636 4609 : for (i = 0; i < large_message_capacity; i++) {
637 4608 : assert_int_equal(large_message[i], 0);
638 : }
639 :
640 1 : libspdm_release_sender_buffer(spdm_context);
641 1 : }
642 :
643 : /**
644 : * Test 7: During an active chunk SEND transfer, a non-chunk, non-GET_VERSION
645 : * request should be rejected with UnexpectedRequest error, and
646 : * the chunk transfer sequence should NOT be terminated.
647 : **/
648 1 : static void libspdm_test_responder_receive_send_rsp_case7(void** state)
649 : {
650 : libspdm_return_t status;
651 : libspdm_test_context_t *spdm_test_context;
652 : libspdm_context_t *spdm_context;
653 : size_t response_size;
654 : uint8_t *response;
655 : spdm_error_response_t *spdm_response;
656 : spdm_message_header_t spdm_request;
657 : void *message;
658 : size_t message_size;
659 : uint32_t transport_header_size;
660 :
661 1 : spdm_test_context = *state;
662 1 : spdm_context = spdm_test_context->spdm_context;
663 1 : spdm_test_context->case_id = 7;
664 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
665 : SPDM_VERSION_NUMBER_SHIFT_BIT;
666 1 : spdm_context->connection_info.connection_state =
667 : LIBSPDM_CONNECTION_STATE_NEGOTIATED;
668 1 : spdm_context->local_context.capability.flags |=
669 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP;
670 1 : spdm_context->connection_info.capability.flags |=
671 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
672 1 : spdm_context->connection_info.capability.data_transfer_size =
673 : LIBSPDM_DATA_TRANSFER_SIZE;
674 1 : spdm_context->connection_info.capability.max_spdm_msg_size =
675 : LIBSPDM_MAX_SPDM_MSG_SIZE;
676 :
677 : /* Simulate an active chunk SEND transfer. */
678 1 : spdm_context->chunk_context.send.chunk_in_use = true;
679 1 : spdm_context->chunk_context.send.chunk_handle = 1;
680 1 : spdm_context->chunk_context.send.chunk_seq_no = 3;
681 :
682 : /* Send a GET_CAPABILITIES request (non-chunk, non-GET_VERSION). */
683 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
684 1 : spdm_request.spdm_version = SPDM_MESSAGE_VERSION_12;
685 1 : spdm_request.request_response_code = SPDM_GET_CAPABILITIES;
686 :
687 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
688 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
689 : &spdm_request, sizeof(spdm_request));
690 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
691 :
692 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void **)&message);
693 1 : response = message;
694 1 : response_size = message_size;
695 1 : libspdm_zero_mem(response, response_size);
696 :
697 1 : status = libspdm_build_response(spdm_context, NULL, false,
698 : &response_size, (void **)&response);
699 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
700 :
701 1 : transport_header_size =
702 : spdm_context->local_context.capability.transport_header_size;
703 1 : spdm_response = (spdm_error_response_t *)((uint8_t *)message + transport_header_size);
704 :
705 : /* Verify error UnexpectedRequest is returned. */
706 1 : assert_int_equal(spdm_response->header.request_response_code, SPDM_ERROR);
707 1 : assert_int_equal(spdm_response->header.param1,
708 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST);
709 :
710 : /* Verify chunk SEND transfer sequence is NOT terminated. */
711 1 : assert_true(spdm_context->chunk_context.send.chunk_in_use);
712 1 : assert_int_equal(spdm_context->chunk_context.send.chunk_handle, 1);
713 1 : assert_int_equal(spdm_context->chunk_context.send.chunk_seq_no, 3);
714 :
715 1 : libspdm_release_sender_buffer(spdm_context);
716 :
717 : /* Clean up chunk state for subsequent tests. */
718 1 : spdm_context->chunk_context.send.chunk_in_use = false;
719 1 : }
720 :
721 : /**
722 : * Test 8: During an active chunk SEND transfer, a GET_VERSION request
723 : * should be allowed to interrupt: the chunk send transfer should be
724 : * terminated and GET_VERSION processed normally.
725 : **/
726 1 : static void libspdm_test_responder_receive_send_rsp_case8(void** state)
727 : {
728 : libspdm_return_t status;
729 : libspdm_test_context_t *spdm_test_context;
730 : libspdm_context_t *spdm_context;
731 : size_t response_size;
732 : uint8_t *response;
733 : spdm_message_header_t *spdm_response;
734 : spdm_get_version_request_t spdm_request;
735 : void *message;
736 : size_t message_size;
737 : uint32_t transport_header_size;
738 : void *scratch_buffer;
739 : size_t scratch_buffer_size;
740 : uint8_t *large_message;
741 : size_t large_message_capacity;
742 : size_t i;
743 :
744 1 : spdm_test_context = *state;
745 1 : spdm_context = spdm_test_context->spdm_context;
746 1 : spdm_test_context->case_id = 8;
747 1 : spdm_context->connection_info.version = SPDM_MESSAGE_VERSION_12 <<
748 : SPDM_VERSION_NUMBER_SHIFT_BIT;
749 1 : spdm_context->connection_info.connection_state =
750 : LIBSPDM_CONNECTION_STATE_NEGOTIATED;
751 1 : spdm_context->local_context.capability.flags |=
752 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP;
753 1 : spdm_context->connection_info.capability.flags |=
754 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP;
755 1 : spdm_context->connection_info.capability.data_transfer_size =
756 : LIBSPDM_DATA_TRANSFER_SIZE;
757 1 : spdm_context->connection_info.capability.max_spdm_msg_size =
758 : LIBSPDM_MAX_SPDM_MSG_SIZE;
759 :
760 : /* Simulate an active chunk SEND transfer. */
761 1 : libspdm_get_scratch_buffer(spdm_context, &scratch_buffer, &scratch_buffer_size);
762 2 : large_message = (uint8_t *)scratch_buffer +
763 1 : libspdm_get_scratch_buffer_large_message_offset(spdm_context);
764 1 : large_message_capacity = libspdm_get_scratch_buffer_large_message_capacity(spdm_context);
765 1 : libspdm_set_mem(large_message, large_message_capacity, 0xa5);
766 :
767 1 : spdm_context->chunk_context.send.chunk_in_use = true;
768 1 : spdm_context->chunk_context.send.chunk_handle = 1;
769 1 : spdm_context->chunk_context.send.chunk_seq_no = 3;
770 1 : spdm_context->chunk_context.send.large_message = large_message;
771 1 : spdm_context->chunk_context.send.large_message_size = large_message_capacity;
772 1 : spdm_context->chunk_context.send.large_message_capacity = large_message_capacity;
773 :
774 : /* Send a GET_VERSION request. */
775 1 : libspdm_zero_mem(&spdm_request, sizeof(spdm_request));
776 1 : spdm_request.header.spdm_version = SPDM_MESSAGE_VERSION_10;
777 1 : spdm_request.header.request_response_code = SPDM_GET_VERSION;
778 :
779 1 : libspdm_copy_mem(spdm_context->last_spdm_request,
780 1 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context),
781 : &spdm_request, sizeof(spdm_request));
782 1 : spdm_context->last_spdm_request_size = sizeof(spdm_request);
783 :
784 1 : libspdm_acquire_sender_buffer(spdm_context, &message_size, (void **)&message);
785 1 : response = message;
786 1 : response_size = message_size;
787 1 : libspdm_zero_mem(response, response_size);
788 :
789 1 : status = libspdm_build_response(spdm_context, NULL, false,
790 : &response_size, (void **)&response);
791 1 : assert_int_equal(status, LIBSPDM_STATUS_SUCCESS);
792 :
793 1 : transport_header_size =
794 : spdm_context->local_context.capability.transport_header_size;
795 1 : spdm_response = (spdm_message_header_t *)((uint8_t *)message + transport_header_size);
796 :
797 : /* Verify GET_VERSION was processed: response should be VERSION. */
798 1 : assert_int_equal(spdm_response->request_response_code, SPDM_VERSION);
799 :
800 : /* Verify chunk send transfer was terminated. */
801 1 : assert_false(spdm_context->chunk_context.send.chunk_in_use);
802 1 : assert_int_equal(spdm_context->chunk_context.send.chunk_seq_no, 0);
803 :
804 1 : assert_null(spdm_context->chunk_context.send.large_message);
805 1 : assert_int_equal(spdm_context->chunk_context.send.large_message_size, 0);
806 1 : assert_int_equal(spdm_context->chunk_context.send.large_message_capacity, 0);
807 4609 : for (i = 0; i < large_message_capacity; i++) {
808 4608 : assert_int_equal(large_message[i], 0);
809 : }
810 :
811 1 : libspdm_release_sender_buffer(spdm_context);
812 1 : }
813 :
814 1 : int libspdm_rsp_receive_send_test(void)
815 : {
816 1 : const struct CMUnitTest test_cases[] = {
817 : /* response message size is larger than requester data_transfer_size */
818 : cmocka_unit_test(libspdm_test_responder_receive_send_rsp_case1),
819 : /* response message size is larger than responder sending transmit buffer size */
820 : cmocka_unit_test_setup(libspdm_test_responder_receive_send_rsp_case2,
821 : libspdm_unit_test_group_setup),
822 : #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
823 : /* response message size is larger than responder sending transmit buffer size
824 : * using the new Vendor Defined Message API */
825 : cmocka_unit_test_setup(libspdm_test_responder_receive_send_rsp_case3,
826 : libspdm_unit_test_group_setup),
827 : #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
828 : /* response message size is larger than requester max_spdm_msg_size */
829 : cmocka_unit_test_setup(libspdm_test_responder_receive_send_rsp_case4,
830 : libspdm_unit_test_group_setup),
831 : /* non-chunk request during active chunk GET transfer returns UnexpectedRequest
832 : * and does not terminate chunk transfer */
833 : cmocka_unit_test_setup(libspdm_test_responder_receive_send_rsp_case5,
834 : libspdm_unit_test_group_setup),
835 : /* GET_VERSION during active chunk GET transfer terminates chunk and proceeds */
836 : cmocka_unit_test_setup(libspdm_test_responder_receive_send_rsp_case6,
837 : libspdm_unit_test_group_setup),
838 : /* non-chunk request during active chunk SEND transfer returns UnexpectedRequest
839 : * and does not terminate chunk transfer */
840 : cmocka_unit_test_setup(libspdm_test_responder_receive_send_rsp_case7,
841 : libspdm_unit_test_group_setup),
842 : /* GET_VERSION during active chunk SEND transfer terminates chunk and proceeds */
843 : cmocka_unit_test_setup(libspdm_test_responder_receive_send_rsp_case8,
844 : libspdm_unit_test_group_setup),
845 : };
846 :
847 1 : libspdm_test_context_t test_context = {
848 : LIBSPDM_TEST_CONTEXT_VERSION,
849 : false,
850 : };
851 :
852 1 : libspdm_setup_test_context(&test_context);
853 :
854 1 : return cmocka_run_group_tests(test_cases,
855 : libspdm_unit_test_group_setup,
856 : libspdm_unit_test_group_teardown);
857 : }
858 :
859 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHUNK_CAP */
|