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 : 22 : static spdm_version_number_t libspdm_storage_get_secured_spdm_version(
23 : : spdm_version_number_t secured_message_version)
24 : : {
25 : 22 : 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 : 8 : static uint32_t libspdm_storage_get_max_random_number_count(void)
37 : : {
38 : 8 : 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 : 22 : static uint8_t libspdm_storage_get_sequence_number(uint64_t sequence_number,
55 : : uint8_t *sequence_number_buffer)
56 : : {
57 : 22 : libspdm_copy_mem(sequence_number_buffer, sizeof(uint64_t),
58 : : &sequence_number, sizeof(uint64_t));
59 : :
60 : 22 : 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 : 12 : 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 [ + + ]: 12 : if (*message_size < LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE) {
100 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
101 : : }
102 : :
103 : 10 : num_descriptors = ((uint8_t *)(*message))[0];
104 : :
105 : : /* Check for invalid message with no descriptors (DSP0286 Table 8) */
106 [ + + ]: 10 : if (num_descriptors == 0) {
107 : 2 : spdm_error.session_id = session_id;
108 : 2 : spdm_error.error_code = SPDM_STORAGE_SECURED_MSG_ENCAPSULATED_STATUS_INVALID_CMD;
109 : 2 : libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error);
110 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
111 : : }
112 : :
113 : : /* Currently support handling only a single SPDM descriptor */
114 [ + + ]: 8 : if (num_descriptors > 1) {
115 : 2 : spdm_error.session_id = session_id;
116 : 2 : spdm_error.error_code = SPDM_STORAGE_SECURED_MSG_ENCAPSULATED_STATUS_INVALID_CMD;
117 : 2 : libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error);
118 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
119 : : }
120 : :
121 : 6 : spdm_storage_descriptor_start = ((uint8_t *)(*message)) + (sizeof(uint8_t) * 3);
122 : 6 : descriptor = (void *)spdm_storage_descriptor_start;
123 : :
124 [ + + ]: 10 : for (int i = 0; i < num_descriptors; ++i) {
125 [ + - ]: 6 : switch(descriptor->desc_type) {
126 : 6 : case SPDM_STORAGE_SECURED_MSG_DESCRIPTOR_SPDM:
127 [ - + ]: 6 : 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 [ - + ]: 6 : if (LIBSPDM_STORAGE_SECURED_MESSAGE_NUM_DESCRIPTORS_OFFSET > descriptor->offset)
136 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
137 : :
138 : 6 : spdm_msg_offset = descriptor->offset -
139 : : LIBSPDM_STORAGE_SECURED_MESSAGE_NUM_DESCRIPTORS_OFFSET;
140 [ - + ]: 6 : if (spdm_msg_offset > *message_size)
141 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
142 : :
143 [ + + ]: 6 : if (!is_request_message &&
144 [ + + ]: 4 : descriptor->status != SPDM_STORAGE_SECURED_MSG_ENCAPSULATED_STATUS_SUCCESS)
145 : 2 : return LIBSPDM_STATUS_ERROR_PEER;
146 : :
147 : 4 : 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 : 4 : descriptor = (void *)(spdm_storage_descriptor_start +
157 : 4 : (LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE * i));
158 : : }
159 : :
160 : 4 : *message = ((uint8_t *)*message) + spdm_msg_offset;
161 : 4 : *message_size -= spdm_msg_offset;
162 : :
163 : 4 : 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 : 8 : 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 : 8 : size_t sec_trans_header_size = is_request_message ?
191 [ + + ]: 8 : sizeof(libspdm_storage_transport_virtual_header_t): 0;
192 : : uint8_t* secured_storage_desc_start;
193 : : uint8_t* secured_storage_desc_end;
194 : 8 : 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 : 8 : sec_trans_header_size += sizeof(uint8_t) * 4;
199 : :
200 : 8 : libspdm_zero_mem(*transport_message, *transport_message_size);
201 : 8 : *secured_message = ((uint8_t *)(*transport_message)) + sec_trans_header_size;
202 : 8 : *secured_message_size = *transport_message_size - sec_trans_header_size;
203 : :
204 : 8 : if (*secured_message_size <
205 [ - + ]: 8 : 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 : 8 : secured_storage_desc_start = *secured_message + (4 + 2 + 2 + 2 + 2);
212 : 8 : 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 : 8 : libspdm_copy_mem(secured_storage_desc_end,
220 : 8 : *secured_message_size - LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE,
221 : : *message, *message_size);
222 : 8 : 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 : 8 : libspdm_get_last_spdm_error_struct(spdm_context, &spdm_error);
227 : :
228 : : /* Encode Secured Message Storage Descriptor */
229 : 8 : secured_storage_desc_start[0] = num_descriptors;
230 : : /* 3 reserved bytes before the descriptor begins */
231 : 8 : descriptor = (void *)(secured_storage_desc_start + (sizeof(uint8_t) * 3));
232 : 8 : descriptor->desc_type = SPDM_STORAGE_SECURED_MSG_DESCRIPTOR_SPDM;
233 [ + + ]: 8 : descriptor->status =
234 : : is_request_message ? 0 : spdm_error.error_code;
235 : :
236 : : /* Length of the element this SPDM element */
237 : 8 : 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 : 8 : *message = secured_storage_desc_start;
245 : 8 : *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 : 8 : descriptor->offset = (4 + 4 + 2 + 2 + 2 + 2 +
253 : : LIBSPDM_STORAGE_SECURED_MESSAGE_DESCRIPTOR_MIN_SIZE);
254 : :
255 : 8 : return LIBSPDM_STATUS_SUCCESS;
256 : : }
257 : :
258 : 32 : 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 : 32 : LIBSPDM_ASSERT(transport_message_size >= sizeof(libspdm_storage_transport_virtual_header_t));
270 [ + + ]: 32 : if (transport_message_size <= sizeof(libspdm_storage_transport_virtual_header_t)) {
271 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
272 : : }
273 : :
274 [ - + ]: 30 : if (transport_message_size == 0) {
275 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
276 : : }
277 : :
278 : 30 : storage_header = transport_message;
279 [ + + ]: 30 : if (storage_header->security_protocol != SPDM_STORAGE_SECURITY_PROTOCOL_DMTF) {
280 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
281 : : }
282 : :
283 : 28 : security_protocol_specific = storage_header->security_protocol_specific;
284 : 28 : spsp0 = security_protocol_specific & 0xFF;
285 : 28 : spsp1 = security_protocol_specific >> 8;
286 : :
287 [ + + ]: 28 : if (spsp1 != 0) {
288 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
289 : : }
290 : :
291 [ + + ]: 26 : if (connection_id) {
292 : 2 : *connection_id = spsp0 & 0x03;
293 : : }
294 : 26 : spdm_operation = (spsp0 & 0xFC) >> 2;
295 : :
296 [ + + + ]: 26 : switch (spdm_operation) {
297 : 10 : case SPDM_STORAGE_OPERATION_CODE_DISCOVERY:
298 : : case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO:
299 : : case SPDM_STORAGE_OPERATION_CODE_MESSAGE:
300 [ + - ]: 10 : if (session_id != NULL) {
301 : 10 : *session_id = NULL;
302 : : }
303 : 10 : *message_size = transport_message_size - sizeof(libspdm_storage_transport_virtual_header_t);
304 : 10 : *message = (uint8_t *)transport_message + sizeof(libspdm_storage_transport_virtual_header_t);
305 : 10 : break;
306 : 14 : case SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE:
307 : 14 : LIBSPDM_ASSERT(session_id != NULL);
308 [ - + ]: 14 : if (session_id == NULL) {
309 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
310 : : }
311 [ + + ]: 14 : if (transport_message_size <=
312 : : sizeof(libspdm_storage_transport_virtual_header_t) + sizeof(uint32_t)) {
313 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
314 : : }
315 : 12 : *session_id = (uint32_t *)((uint8_t *)transport_message +
316 : : sizeof(libspdm_storage_transport_virtual_header_t) +
317 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES);
318 : 12 : *message_size = transport_message_size - sizeof(libspdm_storage_transport_virtual_header_t) -
319 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
320 : 12 : *message = (uint8_t *)transport_message + sizeof(libspdm_storage_transport_virtual_header_t) +
321 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
322 : 12 : break;
323 : 2 : default:
324 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
325 : : }
326 : :
327 : 22 : return LIBSPDM_STATUS_SUCCESS;
328 : : }
329 : :
330 : 36 : libspdm_return_t libspdm_transport_storage_decode_message(
331 : : void *spdm_context, uint32_t **session_id,
332 : : bool *is_app_message, bool is_request_message,
333 : : size_t transport_message_size, void *transport_message,
334 : : size_t *message_size, void **message)
335 : : {
336 : : libspdm_return_t status;
337 : : uint32_t *secured_message_session_id;
338 : : uint8_t *secured_message;
339 : : size_t secured_message_size;
340 : : libspdm_secured_message_callbacks_t spdm_secured_message_callbacks;
341 : : void *secured_message_context;
342 : : libspdm_error_struct_t spdm_error;
343 : :
344 : 36 : spdm_error.error_code = 0;
345 : 36 : spdm_error.session_id = 0;
346 : 36 : libspdm_set_last_spdm_error_struct(spdm_context, &spdm_error);
347 : :
348 : 36 : spdm_secured_message_callbacks.version =
349 : : LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION;
350 : 36 : spdm_secured_message_callbacks.get_sequence_number =
351 : : libspdm_storage_get_sequence_number;
352 : 36 : spdm_secured_message_callbacks.get_max_random_number_count =
353 : : libspdm_storage_get_max_random_number_count;
354 : 36 : spdm_secured_message_callbacks.get_secured_spdm_version =
355 : : libspdm_storage_get_secured_spdm_version;
356 : :
357 [ + - - + ]: 36 : if ((session_id == NULL) || (is_app_message == NULL)) {
358 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
359 : : }
360 : 36 : *is_app_message = false;
361 : :
362 : 36 : secured_message_session_id = NULL;
363 : :
364 [ + + ]: 36 : if (!is_request_message) {
365 : : /*
366 : : * Storage response messages are not transport encoded, this is the SPDM
367 : : * message, and shall be processed as such. Which also means that there
368 : : * is no way from the response to determine if it's secure or not, instead
369 : : * use internal state to determine.
370 : : */
371 : : /* Expecting a secured message */
372 [ + + ]: 10 : if (*session_id != NULL) {
373 [ + + ]: 8 : if (transport_message_size <
374 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES + sizeof(uint32_t)) {
375 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
376 : : }
377 : 6 : **session_id = libspdm_read_uint32(
378 : : (const uint8_t *)transport_message +
379 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES);
380 : :
381 : : secured_message_context =
382 : 6 : libspdm_get_secured_message_context_via_session_id(
383 : 6 : spdm_context, **session_id);
384 [ + + ]: 6 : if (secured_message_context == NULL) {
385 : 2 : spdm_error.error_code = SPDM_ERROR_CODE_INVALID_SESSION;
386 : 2 : spdm_error.session_id = **session_id;
387 : 2 : libspdm_set_last_spdm_error_struct(spdm_context,
388 : : &spdm_error);
389 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
390 : : }
391 : :
392 : : /*
393 : : * Secured message to message
394 : : *
395 : : * DSP0286 specifies 4 reserved bytes at the start of a secured
396 : : * message. Skip that for decoding.
397 : : */
398 : 4 : status = libspdm_decode_secured_message(
399 : 4 : secured_message_context, **session_id,
400 : : is_request_message,
401 : : transport_message_size - LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
402 : : ((uint8_t *)transport_message) +
403 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
404 : : message_size, message, &spdm_secured_message_callbacks);
405 : :
406 [ - + ]: 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
407 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
408 : : "libspdm_decode_secured_message - %x\n", status));
409 : 0 : libspdm_secured_message_get_last_spdm_error_struct(
410 : : secured_message_context, &spdm_error);
411 : 0 : libspdm_set_last_spdm_error_struct(spdm_context,
412 : : &spdm_error);
413 : 0 : return status;
414 : : }
415 : :
416 : 4 : status = libspdm_storage_secured_message_decode(spdm_context, **session_id, message_size,
417 : : message, is_request_message);
418 [ + + ]: 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
419 : 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
420 : : "libspdm_storage_secured_message_decode - %x\n", status));
421 : 2 : return status;
422 : : }
423 : :
424 : : } else {
425 : 2 : *message_size = transport_message_size;
426 : 2 : *message = transport_message;
427 : 2 : *session_id = NULL;
428 : : };
429 : 4 : return LIBSPDM_STATUS_SUCCESS;
430 : : } else {
431 : : /* Storage requests need to be transport encoded/decoded */
432 : 26 : status = libspdm_storage_decode_message(
433 : : &secured_message_session_id, 0, transport_message_size,
434 : : transport_message, &secured_message_size, (void **)&secured_message);
435 : :
436 [ + + ]: 26 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
437 : 10 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_decode_message - %x\n", status));
438 : 10 : return status;
439 : : }
440 : :
441 [ + + ]: 16 : if (secured_message_session_id != NULL) {
442 : 12 : *session_id = secured_message_session_id;
443 : :
444 : : secured_message_context =
445 : 12 : libspdm_get_secured_message_context_via_session_id(
446 : : spdm_context, *secured_message_session_id);
447 [ + + ]: 12 : if (secured_message_context == NULL) {
448 : 2 : spdm_error.error_code = SPDM_ERROR_CODE_INVALID_SESSION;
449 : 2 : spdm_error.session_id = *secured_message_session_id;
450 : 2 : libspdm_set_last_spdm_error_struct(spdm_context,
451 : : &spdm_error);
452 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
453 : : }
454 : :
455 : : /* Secured message to message*/
456 : 10 : status = libspdm_decode_secured_message(
457 : : secured_message_context, *secured_message_session_id,
458 : : is_request_message, secured_message_size,
459 : : (uint8_t *)secured_message,
460 : : message_size, message, &spdm_secured_message_callbacks);
461 [ + + ]: 10 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
462 : 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
463 : : "libspdm_decode_secured_message - %x\n", status));
464 : 2 : libspdm_secured_message_get_last_spdm_error_struct(
465 : : secured_message_context, &spdm_error);
466 : 2 : libspdm_set_last_spdm_error_struct(spdm_context,
467 : : &spdm_error);
468 : 2 : return status;
469 : : }
470 : :
471 : 8 : status = libspdm_storage_secured_message_decode(spdm_context, **session_id, message_size,
472 : : message, is_request_message);
473 [ + + ]: 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
474 : 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
475 : : "libspdm_storage_secured_message_decode - %x\n", status));
476 : 6 : return status;
477 : : }
478 : 2 : return LIBSPDM_STATUS_SUCCESS;
479 : : } else {
480 : : /* get non-secured message*/
481 : 4 : status = libspdm_storage_decode_message(&secured_message_session_id,
482 : : 0,
483 : : transport_message_size,
484 : : transport_message,
485 : : message_size, message);
486 [ - + ]: 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
487 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_decode_message - %x\n",
488 : : status));
489 : 0 : return status;
490 : : }
491 : 4 : LIBSPDM_ASSERT(secured_message_session_id == NULL);
492 : 4 : *session_id = NULL;
493 : 4 : return LIBSPDM_STATUS_SUCCESS;
494 : : }
495 : : }
496 : : }
497 : :
498 : 16 : libspdm_return_t libspdm_storage_encode_message(const uint32_t *session_id,
499 : : uint8_t connection_id,
500 : : size_t message_size, void *message,
501 : : size_t *transport_message_size,
502 : : void **transport_message)
503 : : {
504 : : uint32_t data32;
505 : : libspdm_storage_transport_virtual_header_t *storage_header;
506 : :
507 [ + - + - ]: 16 : if (!transport_message_size || *transport_message_size == 0
508 [ - + ]: 16 : || message_size == 0) {
509 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
510 : : }
511 : :
512 : 16 : LIBSPDM_ASSERT(*transport_message_size >= sizeof(libspdm_storage_transport_virtual_header_t));
513 : :
514 [ + + ]: 16 : if (*transport_message_size < message_size + sizeof(libspdm_storage_transport_virtual_header_t)) {
515 : 2 : *transport_message_size = message_size + sizeof(libspdm_storage_transport_virtual_header_t);
516 : 2 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
517 : : }
518 : :
519 [ + - - + ]: 14 : if (!message || !transport_message) {
520 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
521 : : }
522 : :
523 [ + + ]: 14 : if (connection_id & ~0x03) {
524 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
525 : : }
526 : :
527 : 12 : *transport_message_size = message_size + sizeof(libspdm_storage_transport_virtual_header_t);
528 : 12 : *transport_message = (uint8_t *)message - sizeof(libspdm_storage_transport_virtual_header_t);
529 : 12 : storage_header = *transport_message;
530 : :
531 : 12 : storage_header->security_protocol = SPDM_STORAGE_SECURITY_PROTOCOL_DMTF;
532 : :
533 [ + + ]: 12 : if (session_id != NULL) {
534 : 4 : storage_header->security_protocol_specific = SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE <<
535 : : 2;
536 : 4 : storage_header->security_protocol_specific |= connection_id &
537 : : SPDM_STORAGE_MAX_CONNECTION_ID_MASK;
538 : 4 : libspdm_zero_mem(message, LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES);
539 : 4 : data32 = libspdm_read_uint32(((const uint8_t *)message +
540 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES));
541 : 4 : LIBSPDM_ASSERT(*session_id == data32);
542 [ - + ]: 4 : if (*session_id != data32) {
543 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
544 : : }
545 : : } else {
546 : 8 : storage_header->security_protocol_specific = SPDM_STORAGE_OPERATION_CODE_MESSAGE << 2;
547 : 8 : storage_header->security_protocol_specific |= connection_id &
548 : : SPDM_STORAGE_MAX_CONNECTION_ID_MASK;
549 : : }
550 : :
551 : 12 : return LIBSPDM_STATUS_SUCCESS;
552 : : }
553 : :
554 : 26 : libspdm_return_t libspdm_transport_storage_encode_message(
555 : : void *spdm_context, const uint32_t *session_id,
556 : : bool is_app_message,
557 : : bool is_request_message, size_t message_size, void *message,
558 : : size_t *transport_message_size, void **transport_message)
559 : : {
560 : : libspdm_return_t status;
561 : : uint8_t *secured_message;
562 : : size_t secured_message_size;
563 : : libspdm_secured_message_callbacks_t spdm_secured_message_callbacks;
564 : : void *secured_message_context;
565 : :
566 : 26 : spdm_secured_message_callbacks.version =
567 : : LIBSPDM_SECURED_MESSAGE_CALLBACKS_VERSION;
568 : 26 : spdm_secured_message_callbacks.get_sequence_number =
569 : : libspdm_storage_get_sequence_number;
570 : 26 : spdm_secured_message_callbacks.get_max_random_number_count =
571 : : libspdm_storage_get_max_random_number_count;
572 : 26 : spdm_secured_message_callbacks.get_secured_spdm_version =
573 : : libspdm_storage_get_secured_spdm_version;
574 : :
575 [ + + ]: 26 : if (is_app_message) {
576 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
577 : : }
578 : :
579 [ + - + - ]: 24 : if (!transport_message_size || !transport_message
580 [ + + ]: 24 : || *transport_message_size == 0) {
581 : 4 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
582 : : }
583 : :
584 [ + + ]: 20 : if (session_id != NULL) {
585 : : secured_message_context =
586 : 10 : libspdm_get_secured_message_context_via_session_id(
587 : : spdm_context, *session_id);
588 [ + + ]: 10 : if (secured_message_context == NULL) {
589 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
590 : : }
591 : :
592 : : /* Message to secured message*/
593 : 8 : status = libspdm_storage_secured_message_encode(
594 : : spdm_context, &message_size, &message, &secured_message_size, &secured_message,
595 : : transport_message_size, transport_message, is_request_message);
596 [ - + ]: 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
597 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
598 : : "libspdm_storage_secured_message_encode - %x\n", status));
599 : 0 : return status;
600 : : }
601 : :
602 : 8 : status = libspdm_encode_secured_message(
603 : : secured_message_context, *session_id, is_request_message,
604 : : message_size, message, &secured_message_size,
605 : : secured_message, &spdm_secured_message_callbacks);
606 [ - + ]: 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
607 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR,
608 : : "libspdm_encode_secured_message - %x\n", status));
609 : 0 : return status;
610 : : }
611 : :
612 [ + + ]: 8 : if (!is_request_message) {
613 : : /*
614 : : * Storage response messages are not transport encoded, instead it
615 : : * is just the SPDM message response.
616 : : */
617 : 4 : *transport_message_size = secured_message_size +
618 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
619 : : /* Ensure we allow the 4 reserved bytes to be encapsulated */
620 : 4 : *transport_message = secured_message -
621 : : LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES;
622 : 4 : return LIBSPDM_STATUS_SUCCESS;
623 : : }
624 : :
625 : : /* secured message to secured storage message*/
626 : 4 : status = libspdm_storage_encode_message(
627 : : session_id, 0,
628 : : secured_message_size + LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
629 : 4 : secured_message - LIBSPDM_STORAGE_SECURED_MESSAGE_HEADER_RESERVED_BYTES,
630 : : transport_message_size, transport_message);
631 [ - + ]: 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
632 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_encode_message - %x\n",
633 : : status));
634 : 0 : return status;
635 : : }
636 : : } else {
637 [ + + ]: 10 : if (!is_request_message) {
638 : : /*
639 : : * Storage response messages are not transport encoded, instead it
640 : : * is just the SPDM message response.
641 : : */
642 : 2 : *transport_message_size = message_size;
643 : 2 : *transport_message = message;
644 : 2 : return LIBSPDM_STATUS_SUCCESS;
645 : : }
646 : :
647 : : /* SPDM message to normal storage message*/
648 : 8 : status = libspdm_storage_encode_message(NULL, 0,
649 : : message_size, message,
650 : : transport_message_size,
651 : : transport_message);
652 [ + + ]: 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
653 : 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "transport_encode_message - %x\n",
654 : : status));
655 : 2 : return status;
656 : : }
657 : : }
658 : :
659 : 10 : return LIBSPDM_STATUS_SUCCESS;
660 : : }
661 : :
662 : 26 : libspdm_return_t libspdm_transport_storage_encode_management_cmd(
663 : : uint8_t cmd_direction, uint8_t transport_operation,
664 : : uint8_t connection_id, size_t *transport_message_size,
665 : : size_t *allocation_length, void *transport_message)
666 : : {
667 : : libspdm_storage_transport_virtual_header_t *storage_header;
668 : :
669 [ + - + - ]: 26 : if (!transport_message_size || !allocation_length
670 [ + + ]: 26 : || *transport_message_size == 0) {
671 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
672 : : }
673 : :
674 [ + + ]: 24 : if (*transport_message_size < sizeof(libspdm_storage_transport_virtual_header_t)) {
675 : 2 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
676 : : }
677 : :
678 [ + + ]: 22 : if (connection_id & ~0x03) {
679 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
680 : : }
681 : :
682 [ + + + + ]: 20 : if (!(cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_SEND ||
683 : : cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV)) {
684 : 4 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
685 : : }
686 : :
687 [ + + + ]: 16 : switch (transport_operation) {
688 : 8 : case SPDM_STORAGE_OPERATION_CODE_DISCOVERY:
689 [ + - ]: 8 : if (cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV) {
690 : 8 : *allocation_length = sizeof(spdm_storage_discovery_response_t);
691 [ + + ]: 8 : if (*transport_message_size < sizeof(spdm_storage_discovery_response_t)) {
692 : 2 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
693 : : }
694 : : }
695 : 6 : break;
696 : 4 : case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO:
697 [ + + ]: 4 : if (cmd_direction == LIBSPDM_STORAGE_CMD_DIRECTION_IF_RECV) {
698 : 2 : *allocation_length = sizeof(spdm_storage_pending_info_response_t);
699 [ - + ]: 2 : if (*transport_message_size < sizeof(spdm_storage_pending_info_response_t)) {
700 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
701 : : }
702 : : }
703 : 4 : break;
704 : 4 : default:
705 : 4 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
706 : : }
707 : :
708 : 10 : *transport_message_size = sizeof(libspdm_storage_transport_virtual_header_t);
709 : 10 : libspdm_zero_mem(transport_message, *transport_message_size);
710 : :
711 : 10 : storage_header = transport_message;
712 : 10 : storage_header->security_protocol = SPDM_STORAGE_SECURITY_PROTOCOL_DMTF;
713 : 10 : storage_header->security_protocol_specific = transport_operation << 2;
714 : 10 : storage_header->security_protocol_specific |= connection_id &
715 : : SPDM_STORAGE_MAX_CONNECTION_ID_MASK;
716 : :
717 : 10 : return LIBSPDM_STATUS_SUCCESS;
718 : : }
719 : :
720 : 8 : libspdm_return_t libspdm_transport_storage_encode_discovery_response(
721 : : size_t *transport_message_size,
722 : : void *transport_message)
723 : : {
724 : : spdm_storage_discovery_response_t *discovery_response;
725 : :
726 [ + - + - ]: 8 : if (!transport_message || !transport_message_size
727 [ - + ]: 8 : || *transport_message_size == 0) {
728 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
729 : : }
730 : :
731 [ + + ]: 8 : if (*transport_message_size < sizeof(spdm_storage_discovery_response_t)) {
732 : 4 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
733 : : }
734 : :
735 : 4 : *transport_message_size = sizeof(spdm_storage_discovery_response_t);
736 : 4 : libspdm_zero_mem(transport_message, *transport_message_size);
737 : 4 : discovery_response = transport_message;
738 : :
739 : 4 : discovery_response->storage_response_headers.data_length = (uint16_t)*transport_message_size;
740 : 4 : discovery_response->storage_response_headers.storage_binding_version =
741 : : SPDM_STORAGE_SECURITY_BINDING_VERSION;
742 : : /* 1 supported connection (0's based) */
743 : 4 : discovery_response->conn_params = 0;
744 : 4 : discovery_response->supported_operations = (1 << SPDM_STORAGE_OPERATION_CODE_DISCOVERY)
745 : : | (1 << SPDM_STORAGE_OPERATION_CODE_PENDING_INFO)
746 : : | (1 << SPDM_STORAGE_OPERATION_CODE_MESSAGE)
747 : : | (1 <<
748 : : SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE);
749 : :
750 : 4 : return LIBSPDM_STATUS_SUCCESS;
751 : : }
752 : :
753 : 14 : libspdm_return_t libspdm_transport_storage_encode_pending_info_response(
754 : : size_t *transport_message_size,
755 : : void *transport_message, bool response_pending,
756 : : uint32_t pending_response_length)
757 : : {
758 : : spdm_storage_pending_info_response_t *pending_info_response;
759 : :
760 [ + - + + ]: 14 : if (!transport_message || !transport_message_size
761 [ - + ]: 12 : || *transport_message_size == 0) {
762 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
763 : : }
764 : :
765 [ + + ]: 12 : if (*transport_message_size < sizeof(spdm_storage_pending_info_response_t)) {
766 : 4 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
767 : : }
768 : :
769 : 8 : *transport_message_size = sizeof(spdm_storage_pending_info_response_t);
770 : 8 : libspdm_zero_mem(transport_message, *transport_message_size);
771 : 8 : pending_info_response = transport_message;
772 : :
773 : 8 : pending_info_response->storage_response_headers.data_length = (uint16_t)*transport_message_size;
774 : 8 : pending_info_response->storage_response_headers.storage_binding_version =
775 : : SPDM_STORAGE_SECURITY_BINDING_VERSION;
776 : :
777 [ + + ]: 8 : if (response_pending) {
778 : 4 : pending_info_response->pending_info_flag = (1 << 0);
779 : 4 : pending_info_response->response_length = pending_response_length;
780 : : }
781 : :
782 : 8 : return LIBSPDM_STATUS_SUCCESS;
783 : : }
784 : :
785 : 10 : libspdm_return_t libspdm_transport_storage_decode_management_cmd(
786 : : size_t transport_message_size,
787 : : const void *transport_message,
788 : : uint8_t *transport_command)
789 : : {
790 : : const libspdm_storage_transport_virtual_header_t *storage_header;
791 : : uint16_t security_protocol_specific;
792 : : uint8_t spsp0, spsp1, spdm_operation;
793 : :
794 [ + - - + ]: 10 : if (!transport_message || transport_message_size == 0) {
795 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
796 : : }
797 : :
798 : 10 : LIBSPDM_ASSERT(transport_message_size >= sizeof(libspdm_storage_transport_virtual_header_t));
799 : :
800 [ - + ]: 10 : if (transport_message_size < sizeof(libspdm_storage_transport_virtual_header_t)) {
801 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
802 : : }
803 : :
804 : 10 : storage_header = transport_message;
805 [ + + ]: 10 : if (storage_header->security_protocol != SPDM_STORAGE_SECURITY_PROTOCOL_DMTF) {
806 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
807 : : }
808 : :
809 : 8 : security_protocol_specific = storage_header->security_protocol_specific;
810 : 8 : spsp0 = security_protocol_specific & 0xFF;
811 : 8 : spsp1 = security_protocol_specific >> 8;
812 : :
813 [ + + ]: 8 : if (spsp1 != 0) {
814 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
815 : : }
816 : :
817 : 6 : spdm_operation = (spsp0 & 0xFC) >> 2;
818 : :
819 [ + + ]: 6 : switch (spdm_operation) {
820 : 4 : case SPDM_STORAGE_OPERATION_CODE_DISCOVERY:
821 : : case SPDM_STORAGE_OPERATION_CODE_PENDING_INFO:
822 : : case SPDM_STORAGE_OPERATION_CODE_MESSAGE:
823 : : case SPDM_STORAGE_OPERATION_CODE_SECURED_MESSAGE:
824 : 4 : *transport_command = spdm_operation;
825 : 4 : break;
826 : 2 : default:
827 : 2 : *transport_command = 0;
828 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
829 : : }
830 : :
831 : 4 : return LIBSPDM_STATUS_SUCCESS;
832 : : }
|