Branch data Line data Source code
1 : : /**
2 : : * Copyright Notice:
3 : : * Copyright 2025-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 "library/spdm_transport_storage_lib.h"
8 : : #include "industry_standard/spdm_storage_binding.h"
9 : : #include "internal/libspdm_common_lib.h"
10 : : #include "hal/library/debuglib.h"
11 : : #include "hal/library/memlib.h"
12 : :
13 : : /**
14 : : * This function translates the negotiated secured_message_version to a DSP0277 version.
15 : : *
16 : : * @param secured_message_version The version specified in binding specification and
17 : : * negotiated in KEY_EXCHANGE/KEY_EXCHANGE_RSP.
18 : : *
19 : : * @return The DSP0277 version specified in binding specification,
20 : : * which is bound to secured_message_version.
21 : : */
22 : 0 : static spdm_version_number_t libspdm_storage_get_secured_spdm_version(
23 : : spdm_version_number_t secured_message_version)
24 : : {
25 : 0 : return secured_message_version;
26 : : }
27 : :
28 : : /**
29 : : * Return max random number count in an SPDM secure message.
30 : : *
31 : : * This value is transport layer specific.
32 : : *
33 : : * @return Max random number count in an SPDM secured message.
34 : : * 0 means no random number is required.
35 : : **/
36 : 0 : static uint32_t libspdm_storage_get_max_random_number_count(void)
37 : : {
38 : 0 : return LIBSPDM_STORAGE_MAX_RANDOM_NUMBER_COUNT;
39 : : }
40 : :
41 : : /**
42 : : * Get sequence number in an SPDM secure message.
43 : : *
44 : : * This value is transport layer specific.
45 : : *
46 : : * @param sequence_number The current sequence number used to encode or decode message.
47 : : * @param sequence_number_buffer A buffer to hold the sequence number output used in the secured message.
48 : : * The size in byte of the output buffer shall be 8.
49 : : *
50 : : * @return size in byte of the sequence_number_buffer.
51 : : * It shall be no greater than 8.
52 : : * 0 means no sequence number is required.
53 : : **/
54 : 0 : static uint8_t libspdm_storage_get_sequence_number(uint64_t sequence_number,
55 : : uint8_t *sequence_number_buffer)
56 : : {
57 : 0 : libspdm_copy_mem(sequence_number_buffer, sizeof(uint64_t),
58 : : &sequence_number, sizeof(uint64_t));
59 : :
60 : 0 : return SPDM_STORAGE_SEQUENCE_NUMBER_COUNT;
61 : : }
62 : :
63 : : /**
64 : : * Decode, from a decrypted SPDM Secured Storage message, the SPDM Secured Message Descriptor.
65 : : * This function must only be called after `libspdm_decode_secured_message()` has already
66 : : * processed the encrypted secured message.
67 : : *
68 : : * Limitations:
69 : : * - Implementation only supports parsing a single descriptor
70 : : * - Only supports processing of SPDM Message Descriptor
71 : : *
72 : : * Notes: Encapsulated Error Status shall be set in the response within the Secured descriptor
73 : : * message `status` field, if an erroneous or an unsupported message/field is detected.
74 : : * To accommodate this, keep track of the error state within the transport layer and append the error
75 : : * status when encoding the subsequent response. This is done in `libspdm_transport_storage_encode_message()`
76 : : *
77 : : * @param spdm_context A pointer to the SPDM context.
78 : : * @param session_id Secured Session ID
79 : : * @param message_size SPDM Message Size.
80 : : * On output, size of the real SPDM Message.
81 : : * @param message Decrypted SPDM Message, pointing to the `num descriptors` field of the message.
82 : : * On output, points the start of the real SPDM Message.
83 : : * @param is_request_message Indicates if it is a request message.
84 : : *
85 : : **/
86 : 0 : static libspdm_return_t libspdm_storage_secured_message_decode(
87 : : void *spdm_context, uint32_t session_id, size_t *message_size, void **message,
88 : : bool is_request_message)
89 : : {
90 : : uint8_t *spdm_storage_descriptor_start;
91 : : libspdm_error_struct_t spdm_error;
92 : : uint32_t spdm_msg_offset;
93 : : spdm_storage_secured_message_descriptor *descriptor;
94 : : uint8_t num_descriptors;
95 : :
96 : : /* The num descriptors byte and the single supported descriptor are read
97 : : * below, so the decrypted message must be at least that large before any
98 : : * field is dereferenced. */
99 [ # # ]: 0 : if (*message_size < LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE) {
100 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
101 : : }
102 : :
103 : 0 : num_descriptors = ((uint8_t *)(*message))[0];
104 : :
105 : : /* Check for invalid message with no descriptors (DSP0286 Table 8) */
106 [ # # ]: 0 : if (num_descriptors == 0) {
107 : 0 : spdm_error.session_id = session_id;
108 : 0 : spdm_error.error_code = SPDM_STORAGE_SECURED_MSG_ENCAPSULATED_STATUS_INVALID_CMD;
109 : 0 : libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error);
110 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
111 : : }
112 : :
113 : : /* Currently support handling only a single SPDM descriptor */
114 [ # # ]: 0 : if (num_descriptors > 1) {
115 : 0 : spdm_error.session_id = session_id;
116 : 0 : spdm_error.error_code = SPDM_STORAGE_SECURED_MSG_ENCAPSULATED_STATUS_INVALID_CMD;
117 : 0 : libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error);
118 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
119 : : }
120 : :
121 : 0 : spdm_storage_descriptor_start = ((uint8_t *)(*message)) + (sizeof(uint8_t) * 3);
122 : 0 : descriptor = (void *)spdm_storage_descriptor_start;
123 : :
124 [ # # ]: 0 : for (int i = 0; i < num_descriptors; ++i) {
125 [ # # ]: 0 : switch(descriptor->desc_type) {
126 : 0 : case SPDM_STORAGE_SECURED_MSG_DESCRIPTOR_SPDM:
127 [ # # ]: 0 : if (descriptor->length > *message_size)
128 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
129 : :
130 : : /*
131 : : * Offset is calculated from the start of the Secured
132 : : * Message Data Buffer. `message` points to the start
133 : : * of `num descriptors` within the decoded Secured Message.
134 : : */
135 [ # # ]: 0 : if (LIBSPDM_STORAGE_SECURED_MESSAGE_NUM_DESCRIPTORS_OFFSET > descriptor->offset)
136 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
137 : :
138 : 0 : spdm_msg_offset = descriptor->offset -
139 : : LIBSPDM_STORAGE_SECURED_MESSAGE_NUM_DESCRIPTORS_OFFSET;
140 [ # # ]: 0 : if (spdm_msg_offset > *message_size)
141 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
142 : :
143 [ # # ]: 0 : if (!is_request_message &&
144 [ # # ]: 0 : descriptor->status != SPDM_STORAGE_SECURED_MSG_ENCAPSULATED_STATUS_SUCCESS)
145 : 0 : return LIBSPDM_STATUS_ERROR_PEER;
146 : :
147 : 0 : break;
148 : 0 : default:
149 : 0 : spdm_error.session_id = session_id;
150 : 0 : spdm_error.error_code = SPDM_STORAGE_SECURED_MSG_ENCAPSULATED_STATUS_INVALID_CMD;
151 : 0 : libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error);
152 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
153 : : }
154 : :
155 : : /* Next descriptor */
156 : 0 : descriptor = (void *)(spdm_storage_descriptor_start +
157 : 0 : (LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE * i));
158 : : }
159 : :
160 : 0 : *message = ((uint8_t *)*message) + spdm_msg_offset;
161 : 0 : *message_size -= spdm_msg_offset;
162 : :
163 : 0 : return LIBSPDM_STATUS_SUCCESS;
164 : : }
165 : :
166 : : /**
167 : : * Encode the SPDM Storage Secured Descriptor into an SPDM message. This shall be
168 : : * followed by a call to `libspdm_encode_secured_message()` to encrypt the
169 : : * attached command buffer. This appends exactly one descriptor with the
170 : : * SPDM message type, encapsulating the SPDM message data buffer.
171 : : *
172 : : * @param spdm_context A pointer to the SPDM context.
173 : : * @param message_size SPDM Message Size.
174 : : * @param message SPDM Message.
175 : : * @param secured_message_size On output, size in bytes of the secured message to be encrypted.
176 : : * @param secured_message On output, the start of an SPDM Storage secured message, pointing
177 : : * into the transport message.
178 : : * @param transport_message_size Size in bytes of the transport message buffer.
179 : : * @param transport_message A pointer to a destination buffer to store the transport message.
180 : : * @param is_request_message Indicates if it is a request message.
181 : : *
182 : : **/
183 : 0 : static libspdm_return_t libspdm_storage_secured_message_encode(
184 : : void *spdm_context, size_t *message_size, void **message,
185 : : size_t *secured_message_size, uint8_t **secured_message,
186 : : size_t *transport_message_size, void **transport_message,
187 : : bool is_request_message)
188 : : {
189 : : libspdm_error_struct_t spdm_error;
190 : 0 : size_t sec_trans_header_size = is_request_message ?
191 [ # # ]: 0 : sizeof(libspdm_storage_transport_virtual_header_t): 0;
192 : : uint8_t* secured_storage_desc_start;
193 : : uint8_t* secured_storage_desc_end;
194 : 0 : uint8_t num_descriptors = 1;
195 : : spdm_storage_secured_message_descriptor *descriptor;
196 : :
197 : : /* DSP0286 Specifies 4 Reserved bytes at the start of a secured message */
198 : 0 : sec_trans_header_size += sizeof(uint8_t) * 4;
199 : :
200 : 0 : libspdm_zero_mem(*transport_message, *transport_message_size);
201 : 0 : *secured_message = ((uint8_t *)(*transport_message)) + sec_trans_header_size;
202 : 0 : *secured_message_size = *transport_message_size - sec_trans_header_size;
203 : :
204 : 0 : if (*secured_message_size <
205 [ # # ]: 0 : LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE + *message_size) {
206 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
207 : : "No space in transport message buffer to append storage descriptors"));
208 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
209 : : }
210 : :
211 : 0 : secured_storage_desc_start = *secured_message + (4 + 2 + 2 + 2 + 2);
212 : 0 : secured_storage_desc_end = secured_storage_desc_start +
213 : : LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE;
214 : :
215 : : /*
216 : : * Move the secured message within the transport message to allow space for
217 : : * descriptors and zero the descriptor fields.
218 : : */
219 : 0 : libspdm_copy_mem(secured_storage_desc_end,
220 : 0 : *secured_message_size - LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE,
221 : : *message, *message_size);
222 : 0 : libspdm_zero_mem(secured_storage_desc_start,
223 : : LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE);
224 : :
225 : : /* Retrieve secured session encapsulated error status if any */
226 : 0 : libspdm_get_last_spdm_error_struct(spdm_context, &spdm_error);
227 : :
228 : : /* Encode Secured Message Storage Descriptor */
229 : 0 : secured_storage_desc_start[0] = num_descriptors;
230 : : /* 3 reserved bytes before the descriptor begins */
231 : 0 : descriptor = (void *)(secured_storage_desc_start + (sizeof(uint8_t) * 3));
232 : 0 : descriptor->desc_type = SPDM_STORAGE_SECURED_MSG_DESCRIPTOR_SPDM;
233 [ # # ]: 0 : descriptor->status =
234 : : is_request_message ? 0 : spdm_error.error_code;
235 : :
236 : : /* Length of the element this SPDM element */
237 : 0 : descriptor->length = (uint32_t)*message_size;
238 : :
239 : : /*
240 : : * The updated `message` means subsequent calls to `libspdm_encode_secured_message()`
241 : : * also encode this `descriptor` as part of the data buffer as specified
242 : : * by DSP0286: 158.
243 : : */
244 : 0 : *message = secured_storage_desc_start;
245 : 0 : *message_size += LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE;
246 : :
247 : : /*
248 : : * Only a single descriptor is used, the offset into the secure message data
249 : : * element is calculated as per Table 7 of DSP0286. That is, from the start of
250 : : * the SPDM Storage Secured Message Header
251 : : */
252 : 0 : descriptor->offset = (4 + 4 + 2 + 2 + 2 + 2 +
253 : : LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE);
254 : :
255 : 0 : return LIBSPDM_STATUS_SUCCESS;
256 : : }
257 : :
258 : 2 : libspdm_return_t libspdm_storage_decode_message(uint32_t **session_id,
259 : : uint8_t *connection_id,
260 : : size_t transport_message_size,
261 : : void *transport_message,
262 : : size_t *message_size,
263 : : void **message)
264 : : {
265 : : const libspdm_storage_transport_virtual_header_t *storage_header;
266 : : uint16_t security_protocol_specific;
267 : : uint8_t spsp0, spsp1, spdm_operation;
268 : :
269 [ - + ]: 2 : LIBSPDM_ASSERT(transport_message_size >= sizeof(libspdm_storage_transport_virtual_header_t));
270 [ - + ]: 2 : if (transport_message_size <= sizeof(libspdm_storage_transport_virtual_header_t)) {
271 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
272 : : }
273 : :
274 [ - + ]: 2 : if (transport_message_size == 0) {
275 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
276 : : }
277 : :
278 : 2 : storage_header = transport_message;
279 [ - + ]: 2 : if (storage_header->security_protocol != SPDM_STORAGE_SECURITY_PROTOCOL_DMTF) {
280 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
281 : : }
282 : :
283 : : #if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
284 : : security_protocol_specific = libspdm_byte_swap_16(storage_header->security_protocol_specific);
285 : : #else
286 : 2 : security_protocol_specific = storage_header->security_protocol_specific;
287 : : #endif
288 : 2 : spsp0 = security_protocol_specific & 0xFF;
289 : 2 : spsp1 = security_protocol_specific >> 8;
290 : :
291 [ - + ]: 2 : if (spsp1 != 0) {
292 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
293 : : }
294 : :
295 [ - + ]: 2 : if (connection_id) {
296 : 0 : *connection_id = spsp0 & 0x03;
297 : : }
298 : 2 : spdm_operation = (spsp0 & 0xFC) >> 2;
299 : :
300 [ + - - ]: 2 : switch (spdm_operation) {
301 : 2 : case SPDM_STORAGE_OPERATION_CODE_DISCOVERY:
302 : : case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO:
303 : : case SPDM_STORAGE_OPERATION_CODE_MESSAGE:
304 [ + - ]: 2 : if (session_id != NULL) {
305 : 2 : *session_id = NULL;
306 : : }
307 : 2 : *message_size = transport_message_size - sizeof(libspdm_storage_transport_virtual_header_t);
308 : 2 : *message = (uint8_t *)transport_message + sizeof(libspdm_storage_transport_virtual_header_t);
309 : 2 : break;
310 : 0 : case SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE:
311 [ # # ]: 0 : LIBSPDM_ASSERT(session_id != NULL);
312 [ # # ]: 0 : if (session_id == NULL) {
313 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
314 : : }
315 [ # # ]: 0 : if (transport_message_size <=
316 : : sizeof(libspdm_storage_transport_virtual_header_t) + sizeof(uint32_t)) {
317 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
318 : : }
319 : 0 : *session_id = (uint32_t *)((uint8_t *)transport_message +
320 : : sizeof(libspdm_storage_transport_virtual_header_t) +
321 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES);
322 : 0 : *message_size = transport_message_size - sizeof(libspdm_storage_transport_virtual_header_t) -
323 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
324 : 0 : *message = (uint8_t *)transport_message + sizeof(libspdm_storage_transport_virtual_header_t) +
325 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
326 : 0 : break;
327 : 0 : default:
328 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
329 : : }
330 : :
331 : 2 : return LIBSPDM_STATUS_SUCCESS;
332 : : }
333 : :
334 : 1 : libspdm_return_t libspdm_transport_storage_decode_message(
335 : : void *spdm_context, uint32_t **session_id,
336 : : bool *is_app_message, bool is_request_message,
337 : : size_t transport_message_size, void *transport_message,
338 : : size_t *message_size, void **message)
339 : : {
340 : : libspdm_return_t status;
341 : : uint32_t *secured_message_session_id;
342 : : uint8_t *secured_message;
343 : : size_t secured_message_size;
344 : : libspdm_secured_message_callbacks_t spdm_secured_message_callbacks;
345 : : void *secured_message_context;
346 : : libspdm_error_struct_t spdm_error;
347 : :
348 : 1 : spdm_error.error_code = 0;
349 : 1 : spdm_error.session_id = 0;
350 : 1 : libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error);
351 : :
352 : 1 : spdm_secured_message_callbacks.version =
353 : : LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION;
354 : 1 : spdm_secured_message_callbacks.get_sequence_number =
355 : : libspdm_storage_get_sequence_number;
356 : 1 : spdm_secured_message_callbacks.get_max_random_number_count =
357 : : libspdm_storage_get_max_random_number_count;
358 : 1 : spdm_secured_message_callbacks.get_secured_spdm_version =
359 : : libspdm_storage_get_secured_spdm_version;
360 : :
361 [ + - - + ]: 1 : if ((session_id == NULL) || (is_app_message == NULL)) {
362 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
363 : : }
364 : 1 : *is_app_message = false;
365 : :
366 : 1 : secured_message_session_id = NULL;
367 : :
368 [ - + ]: 1 : if (!is_request_message) {
369 : : /*
370 : : * Storage response messages are not transport encoded, this is the SPDM
371 : : * message, and shall be processed as such. Which also means that there
372 : : * is no way from the response to determine if it's secure or not, instead
373 : : * use internal state to determine.
374 : : */
375 : : /* Expecting a secured message */
376 [ # # ]: 0 : if (*session_id != NULL) {
377 [ # # ]: 0 : if (transport_message_size <
378 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES + sizeof(uint32_t)) {
379 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
380 : : }
381 : 0 : **session_id = libspdm_read_uint32(
382 : : (const uint8_t *)transport_message +
383 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES);
384 : :
385 : : secured_message_context =
386 : 0 : libspdm_get_secured_message_context_via_session_id(
387 : 0 : spdm_context, **session_id);
388 [ # # ]: 0 : if (secured_message_context == NULL) {
389 : 0 : spdm_error.error_code = SPDM_ERROR_CODE_INVALID_SESSION;
390 : 0 : spdm_error.session_id = **session_id;
391 : 0 : libspdm_set_last_spdm_error_struct(spdm_context,
392 : : &spdm_error);
393 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
394 : : }
395 : :
396 : : /*
397 : : * Secured message to message
398 : : *
399 : : * DSP0286 specifies 4 reserved bytes at the start of a secured
400 : : * message. Skip that for decoding.
401 : : */
402 : 0 : status = libspdm_decode_secured_message(
403 : 0 : secured_message_context, **session_id,
404 : : is_request_message,
405 : : transport_message_size - LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
406 : : ((uint8_t *)transport_message) +
407 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
408 : : message_size, message, &spdm_secured_message_callbacks);
409 : :
410 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
411 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
412 : : "libspdm_decode_secured_message - %x\n", status));
413 : 0 : libspdm_secured_message_get_last_spdm_error_struct(
414 : : secured_message_context, &spdm_error);
415 : 0 : libspdm_set_last_spdm_error_struct(spdm_context,
416 : : &spdm_error);
417 : 0 : return status;
418 : : }
419 : :
420 : 0 : status = libspdm_storage_secured_message_decode(spdm_context, **session_id, message_size,
421 : : message, is_request_message);
422 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
423 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
424 : : "libspdm_storage_secured_message_decode - %x\n", status));
425 : 0 : return status;
426 : : }
427 : :
428 : : } else {
429 : 0 : *message_size = transport_message_size;
430 : 0 : *message = transport_message;
431 : 0 : *session_id = NULL;
432 : : };
433 : 0 : return LIBSPDM_STATUS_SUCCESS;
434 : : } else {
435 : : /* Storage requests need to be transport encoded/decoded */
436 : 1 : status = libspdm_storage_decode_message(
437 : : &secured_message_session_id, 0, transport_message_size,
438 : : transport_message, &secured_message_size, (void **)&secured_message);
439 : :
440 [ - + ]: 1 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
441 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_decode_message - %x\n", status));
442 : 0 : return status;
443 : : }
444 : :
445 [ - + ]: 1 : if (secured_message_session_id != NULL) {
446 : 0 : *session_id = secured_message_session_id;
447 : :
448 : : secured_message_context =
449 : 0 : libspdm_get_secured_message_context_via_session_id(
450 : : spdm_context, *secured_message_session_id);
451 [ # # ]: 0 : if (secured_message_context == NULL) {
452 : 0 : spdm_error.error_code = SPDM_ERROR_CODE_INVALID_SESSION;
453 : 0 : spdm_error.session_id = *secured_message_session_id;
454 : 0 : libspdm_set_last_spdm_error_struct(spdm_context,
455 : : &spdm_error);
456 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
457 : : }
458 : :
459 : : /* Secured message to message*/
460 : 0 : status = libspdm_decode_secured_message(
461 : : secured_message_context, *secured_message_session_id,
462 : : is_request_message, secured_message_size,
463 : : (uint8_t *)secured_message,
464 : : message_size, message, &spdm_secured_message_callbacks);
465 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
466 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
467 : : "libspdm_decode_secured_message - %x\n", status));
468 : 0 : libspdm_secured_message_get_last_spdm_error_struct(
469 : : secured_message_context, &spdm_error);
470 : 0 : libspdm_set_last_spdm_error_struct(spdm_context,
471 : : &spdm_error);
472 : 0 : return status;
473 : : }
474 : :
475 : 0 : status = libspdm_storage_secured_message_decode(spdm_context, **session_id, message_size,
476 : : message, is_request_message);
477 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
478 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
479 : : "libspdm_storage_secured_message_decode - %x\n", status));
480 : 0 : return status;
481 : : }
482 : 0 : return LIBSPDM_STATUS_SUCCESS;
483 : : } else {
484 : : /* get non-secured message*/
485 : 1 : status = libspdm_storage_decode_message(&secured_message_session_id,
486 : : 0,
487 : : transport_message_size,
488 : : transport_message,
489 : : message_size, message);
490 [ - + ]: 1 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
491 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_decode_message - %x\n",
492 : : status));
493 : 0 : return status;
494 : : }
495 [ - + ]: 1 : LIBSPDM_ASSERT(secured_message_session_id == NULL);
496 : 1 : *session_id = NULL;
497 : 1 : return LIBSPDM_STATUS_SUCCESS;
498 : : }
499 : : }
500 : : }
501 : :
502 : 2 : libspdm_return_t libspdm_storage_encode_message(const uint32_t *session_id,
503 : : uint8_t connection_id,
504 : : size_t message_size, void *message,
505 : : size_t *transport_message_size,
506 : : void **transport_message)
507 : : {
508 : : uint32_t data32;
509 : : libspdm_storage_transport_virtual_header_t *storage_header;
510 : :
511 [ + - + - ]: 2 : if (!transport_message_size || *transport_message_size == 0
512 [ - + ]: 2 : || message_size == 0) {
513 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
514 : : }
515 : :
516 [ - + ]: 2 : LIBSPDM_ASSERT(*transport_message_size >= sizeof(libspdm_storage_transport_virtual_header_t));
517 : :
518 [ - + ]: 2 : if (*transport_message_size < message_size + sizeof(libspdm_storage_transport_virtual_header_t)) {
519 : 0 : *transport_message_size = message_size + sizeof(libspdm_storage_transport_virtual_header_t);
520 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
521 : : }
522 : :
523 [ + - - + ]: 2 : if (!message || !transport_message) {
524 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
525 : : }
526 : :
527 [ - + ]: 2 : if (connection_id & ~0x03) {
528 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
529 : : }
530 : :
531 : 2 : *transport_message_size = message_size + sizeof(libspdm_storage_transport_virtual_header_t);
532 : 2 : *transport_message = (uint8_t *)message - sizeof(libspdm_storage_transport_virtual_header_t);
533 : 2 : storage_header = *transport_message;
534 : :
535 : 2 : storage_header->security_protocol = SPDM_STORAGE_SECURITY_PROTOCOL_DMTF;
536 : :
537 [ - + ]: 2 : if (session_id != NULL) {
538 : 0 : storage_header->security_protocol_specific = SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE <<
539 : : 2;
540 : 0 : storage_header->security_protocol_specific |= connection_id &
541 : : SPDM_STORAGE_MAX_CONNECTION_ID_MASK;
542 : 0 : libspdm_zero_mem(message, LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES);
543 : 0 : data32 = libspdm_read_uint32(((const uint8_t *)message +
544 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES));
545 [ # # ]: 0 : LIBSPDM_ASSERT(*session_id == data32);
546 [ # # ]: 0 : if (*session_id != data32) {
547 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
548 : : }
549 : : } else {
550 : 2 : storage_header->security_protocol_specific = SPDM_STORAGE_OPERATION_CODE_MESSAGE << 2;
551 : 2 : storage_header->security_protocol_specific |= connection_id &
552 : : SPDM_STORAGE_MAX_CONNECTION_ID_MASK;
553 : : }
554 : :
555 : : #if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
556 : : storage_header->security_protocol_specific = libspdm_byte_swap_16(
557 : : storage_header->security_protocol_specific);
558 : : #endif
559 : :
560 : 2 : return LIBSPDM_STATUS_SUCCESS;
561 : : }
562 : :
563 : 3 : libspdm_return_t libspdm_transport_storage_encode_message(
564 : : void *spdm_context, const uint32_t *session_id,
565 : : bool is_app_message,
566 : : bool is_request_message, size_t message_size, void *message,
567 : : size_t *transport_message_size, void **transport_message)
568 : : {
569 : : libspdm_return_t status;
570 : : uint8_t *secured_message;
571 : : size_t secured_message_size;
572 : : libspdm_secured_message_callbacks_t spdm_secured_message_callbacks;
573 : : void *secured_message_context;
574 : :
575 : 3 : spdm_secured_message_callbacks.version =
576 : : LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION;
577 : 3 : spdm_secured_message_callbacks.get_sequence_number =
578 : : libspdm_storage_get_sequence_number;
579 : 3 : spdm_secured_message_callbacks.get_max_random_number_count =
580 : : libspdm_storage_get_max_random_number_count;
581 : 3 : spdm_secured_message_callbacks.get_secured_spdm_version =
582 : : libspdm_storage_get_secured_spdm_version;
583 : :
584 [ - + ]: 3 : if (is_app_message) {
585 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
586 : : }
587 : :
588 [ + - + - ]: 3 : if (!transport_message_size || !transport_message
589 [ + + ]: 3 : || *transport_message_size == 0) {
590 : 1 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
591 : : }
592 : :
593 [ - + ]: 2 : if (session_id != NULL) {
594 : : secured_message_context =
595 : 0 : libspdm_get_secured_message_context_via_session_id(
596 : : spdm_context, *session_id);
597 [ # # ]: 0 : if (secured_message_context == NULL) {
598 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
599 : : }
600 : :
601 : : /* Message to secured message*/
602 : 0 : status = libspdm_storage_secured_message_encode(
603 : : spdm_context, &message_size, &message, &secured_message_size, &secured_message,
604 : : transport_message_size, transport_message, is_request_message);
605 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
606 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
607 : : "libspdm_storage_secured_message_encode - %x\n", status));
608 : 0 : return status;
609 : : }
610 : :
611 : 0 : status = libspdm_encode_secured_message(
612 : : secured_message_context, *session_id, is_request_message,
613 : : message_size, message, &secured_message_size,
614 : : secured_message, &spdm_secured_message_callbacks);
615 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
616 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
617 : : "libspdm_encode_secured_message - %x\n", status));
618 : 0 : return status;
619 : : }
620 : :
621 [ # # ]: 0 : if (!is_request_message) {
622 : : /*
623 : : * Storage response messages are not transport encoded, instead it
624 : : * is just the SPDM message response.
625 : : */
626 : 0 : *transport_message_size = secured_message_size +
627 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
628 : : /* Ensure we allow the 4 reserved bytes to be encapsulated */
629 : 0 : *transport_message = secured_message -
630 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
631 : 0 : return LIBSPDM_STATUS_SUCCESS;
632 : : }
633 : :
634 : : /* secured message to secured storage message*/
635 : 0 : status = libspdm_storage_encode_message(
636 : : session_id, 0,
637 : : secured_message_size + LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
638 : 0 : secured_message - LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
639 : : transport_message_size, transport_message);
640 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
641 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_encode_message - %x\n",
642 : : status));
643 : 0 : return status;
644 : : }
645 : : } else {
646 [ - + ]: 2 : if (!is_request_message) {
647 : : /*
648 : : * Storage response messages are not transport encoded, instead it
649 : : * is just the SPDM message response.
650 : : */
651 : 0 : *transport_message_size = message_size;
652 : 0 : *transport_message = message;
653 : 0 : return LIBSPDM_STATUS_SUCCESS;
654 : : }
655 : :
656 : : /* SPDM message to normal storage message*/
657 : 2 : status = libspdm_storage_encode_message(NULL, 0,
658 : : message_size, message,
659 : : transport_message_size,
660 : : transport_message);
661 [ - + ]: 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
662 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_encode_message - %x\n",
663 : : status));
664 : 0 : return status;
665 : : }
666 : : }
667 : :
668 : 2 : return LIBSPDM_STATUS_SUCCESS;
669 : : }
670 : :
671 : 6 : libspdm_return_t libspdm_transport_storage_encode_management_cmd(
672 : : uint8_t cmd_direction, uint8_t transport_operation,
673 : : uint8_t connection_id, size_t *transport_message_size,
674 : : size_t *allocation_length, void *transport_message)
675 : : {
676 : : libspdm_storage_transport_virtual_header_t *storage_header;
677 : :
678 [ + - + - ]: 6 : if (!transport_message_size || !allocation_length
679 [ + + ]: 6 : || *transport_message_size == 0) {
680 : 1 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
681 : : }
682 : :
683 [ - + ]: 5 : if (*transport_message_size < sizeof(libspdm_storage_transport_virtual_header_t)) {
684 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
685 : : }
686 : :
687 [ - + ]: 5 : if (connection_id & ~0x03) {
688 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
689 : : }
690 : :
691 [ + + + + ]: 5 : if (!(cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_SEND ||
692 : : cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV)) {
693 : 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
694 : : }
695 : :
696 [ + + + ]: 4 : switch (transport_operation) {
697 : 2 : case SPDM_STORAGE_OPERATION_CODE_DISCOVERY:
698 [ + - ]: 2 : if (cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV) {
699 : 2 : *allocation_length = sizeof(spdm_storage_discovery_response_t);
700 [ - + ]: 2 : if (*transport_message_size < sizeof(spdm_storage_discovery_response_t)) {
701 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
702 : : }
703 : : }
704 : 2 : break;
705 : 1 : case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO:
706 [ - + ]: 1 : if (cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV) {
707 : 0 : *allocation_length = sizeof(spdm_storage_pending_info_response_t);
708 [ # # ]: 0 : if (*transport_message_size < sizeof(spdm_storage_pending_info_response_t)) {
709 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
710 : : }
711 : : }
712 : 1 : break;
713 : 1 : default:
714 : 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
715 : : }
716 : :
717 : 3 : *transport_message_size = sizeof(libspdm_storage_transport_virtual_header_t);
718 : 3 : libspdm_zero_mem(transport_message, *transport_message_size);
719 : :
720 : 3 : storage_header = transport_message;
721 : 3 : storage_header->security_protocol = SPDM_STORAGE_SECURITY_PROTOCOL_DMTF;
722 : 3 : storage_header->security_protocol_specific = transport_operation << 2;
723 : 3 : storage_header->security_protocol_specific |= connection_id &
724 : : SPDM_STORAGE_MAX_CONNECTION_ID_MASK;
725 : :
726 : : #if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
727 : : storage_header->security_protocol_specific = libspdm_byte_swap_16(
728 : : storage_header->security_protocol_specific);
729 : : #endif
730 : :
731 : 3 : return LIBSPDM_STATUS_SUCCESS;
732 : : }
733 : :
734 : 2 : libspdm_return_t libspdm_transport_storage_encode_discovery_response(
735 : : size_t *transport_message_size,
736 : : void *transport_message)
737 : : {
738 : : spdm_storage_discovery_response_t *discovery_response;
739 : :
740 [ + - + - ]: 2 : if (!transport_message || !transport_message_size
741 [ - + ]: 2 : || *transport_message_size == 0) {
742 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
743 : : }
744 : :
745 [ + + ]: 2 : if (*transport_message_size < sizeof(spdm_storage_discovery_response_t)) {
746 : 1 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
747 : : }
748 : :
749 : 1 : *transport_message_size = sizeof(spdm_storage_discovery_response_t);
750 : 1 : libspdm_zero_mem(transport_message, *transport_message_size);
751 : 1 : discovery_response = transport_message;
752 : :
753 : 1 : discovery_response->storage_response_headers.data_length = (uint16_t)*transport_message_size;
754 : 1 : discovery_response->storage_response_headers.storage_binding_version =
755 : : SPDM_STORAGE_SECURITY_BINDING_VERSION;
756 : : /* 1 supported connection (0's based) */
757 : 1 : discovery_response->conn_params = 0;
758 : 1 : discovery_response->supported_operations = (1 << SPDM_STORAGE_OPERATION_CODE_DISCOVERY)
759 : : | (1 << SPDM_STORAGE_OPERATION_CODE_PENDING_INFO)
760 : : | (1 << SPDM_STORAGE_OPERATION_CODE_MESSAGE)
761 : : | (1 <<
762 : : SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE);
763 : :
764 : 1 : return LIBSPDM_STATUS_SUCCESS;
765 : : }
766 : :
767 : 4 : libspdm_return_t libspdm_transport_storage_encode_pending_info_response(
768 : : size_t *transport_message_size,
769 : : void *transport_message, bool response_pending,
770 : : uint32_t pending_response_length)
771 : : {
772 : : spdm_storage_pending_info_response_t *pending_info_response;
773 : :
774 [ + - + + ]: 4 : if (!transport_message || !transport_message_size
775 [ - + ]: 3 : || *transport_message_size == 0) {
776 : 1 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
777 : : }
778 : :
779 [ + + ]: 3 : if (*transport_message_size < sizeof(spdm_storage_pending_info_response_t)) {
780 : 1 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
781 : : }
782 : :
783 : 2 : *transport_message_size = sizeof(spdm_storage_pending_info_response_t);
784 : 2 : libspdm_zero_mem(transport_message, *transport_message_size);
785 : 2 : pending_info_response = transport_message;
786 : :
787 : 2 : pending_info_response->storage_response_headers.data_length = (uint16_t)*transport_message_size;
788 : 2 : pending_info_response->storage_response_headers.storage_binding_version =
789 : : SPDM_STORAGE_SECURITY_BINDING_VERSION;
790 : :
791 [ + + ]: 2 : if (response_pending) {
792 : 1 : pending_info_response->pending_info_flag = (1 << 0);
793 : 1 : pending_info_response->response_length = pending_response_length;
794 : : }
795 : :
796 : 2 : return LIBSPDM_STATUS_SUCCESS;
797 : : }
798 : :
799 : 1 : libspdm_return_t libspdm_transport_storage_decode_management_cmd(
800 : : size_t transport_message_size,
801 : : const void *transport_message,
802 : : uint8_t *transport_command)
803 : : {
804 : : const libspdm_storage_transport_virtual_header_t *storage_header;
805 : : uint16_t security_protocol_specific;
806 : : uint8_t spsp0, spsp1, spdm_operation;
807 : :
808 [ + - - + ]: 1 : if (!transport_message || transport_message_size == 0) {
809 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
810 : : }
811 : :
812 [ - + ]: 1 : LIBSPDM_ASSERT(transport_message_size >= sizeof(libspdm_storage_transport_virtual_header_t));
813 : :
814 [ - + ]: 1 : if (transport_message_size < sizeof(libspdm_storage_transport_virtual_header_t)) {
815 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
816 : : }
817 : :
818 : 1 : storage_header = transport_message;
819 [ - + ]: 1 : if (storage_header->security_protocol != SPDM_STORAGE_SECURITY_PROTOCOL_DMTF) {
820 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
821 : : }
822 : :
823 : : #if __BYTE_ORDER__==__ORDER_BIG_ENDIAN__
824 : : security_protocol_specific = libspdm_byte_swap_16(storage_header->security_protocol_specific);
825 : : #else
826 : 1 : security_protocol_specific = storage_header->security_protocol_specific;
827 : : #endif
828 : 1 : spsp0 = security_protocol_specific & 0xFF;
829 : 1 : spsp1 = security_protocol_specific >> 8;
830 : :
831 [ - + ]: 1 : if (spsp1 != 0) {
832 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
833 : : }
834 : :
835 : 1 : spdm_operation = (spsp0 & 0xFC) >> 2;
836 : :
837 [ + - ]: 1 : switch (spdm_operation) {
838 : 1 : case SPDM_STORAGE_OPERATION_CODE_DISCOVERY:
839 : : case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO:
840 : : case SPDM_STORAGE_OPERATION_CODE_MESSAGE:
841 : : case SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE:
842 : 1 : *transport_command = spdm_operation;
843 : 1 : break;
844 : 0 : default:
845 : 0 : *transport_command = 0;
846 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
847 : : }
848 : :
849 : 1 : return LIBSPDM_STATUS_SUCCESS;
850 : : }
|