Branch data Line data Source code
1 : : /**
2 : : * Copyright Notice:
3 : : * Copyright 2021-2026 DMTF. All rights reserved.
4 : : * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
5 : : **/
6 : :
7 : : #include "internal/libspdm_common_lib.h"
8 : : #include "internal/libspdm_secured_message_lib.h"
9 : :
10 : 576 : size_t libspdm_get_opaque_data_version_selection_data_size(const libspdm_context_t *spdm_context)
11 : : {
12 : : size_t size;
13 : :
14 [ - + ]: 576 : if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
15 : 0 : return 0;
16 : : }
17 : :
18 [ + + ]: 576 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
19 : 80 : size = sizeof(spdm_general_opaque_data_table_header_t) +
20 : : sizeof(secured_message_opaque_element_table_header_t) +
21 : : sizeof(secured_message_opaque_element_version_selection_t);
22 : : } else {
23 : 496 : size = sizeof(secured_message_general_opaque_data_table_header_t) +
24 : : sizeof(secured_message_opaque_element_table_header_t) +
25 : : sizeof(secured_message_opaque_element_version_selection_t);
26 : : }
27 : : /* Add Padding*/
28 : 576 : return (size + 3) & ~3;
29 : : }
30 : :
31 : 1082 : size_t libspdm_get_opaque_data_supported_version_data_size(libspdm_context_t *spdm_context)
32 : : {
33 : : size_t size;
34 : :
35 [ - + ]: 1082 : if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
36 : 0 : return 0;
37 : : }
38 : :
39 [ + + ]: 1082 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
40 : 136 : size = sizeof(spdm_general_opaque_data_table_header_t) +
41 : : sizeof(secured_message_opaque_element_table_header_t) +
42 : : sizeof(secured_message_opaque_element_supported_version_t) +
43 : 136 : sizeof(spdm_version_number_t) *
44 : 136 : spdm_context->local_context.secured_message_version.secured_message_version_count;
45 : : } else {
46 : 946 : size = sizeof(secured_message_general_opaque_data_table_header_t) +
47 : : sizeof(secured_message_opaque_element_table_header_t) +
48 : : sizeof(secured_message_opaque_element_supported_version_t) +
49 : 946 : sizeof(spdm_version_number_t) *
50 : 946 : spdm_context->local_context.secured_message_version.secured_message_version_count;
51 : : }
52 : : /* Add Padding*/
53 : 1082 : return (size + 3) & ~3;
54 : : }
55 : :
56 : 116 : size_t libspdm_get_untrusted_opaque_data_supported_version_data_size(
57 : : libspdm_context_t *spdm_context, uint8_t version_count)
58 : : {
59 : : size_t size;
60 : :
61 [ + + ]: 116 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
62 : 20 : size = sizeof(spdm_general_opaque_data_table_header_t) +
63 : : sizeof(secured_message_opaque_element_table_header_t) +
64 : : sizeof(secured_message_opaque_element_supported_version_t) +
65 : 20 : sizeof(spdm_version_number_t) * version_count;
66 : : } else {
67 : 96 : size = sizeof(secured_message_general_opaque_data_table_header_t) +
68 : : sizeof(secured_message_opaque_element_table_header_t) +
69 : : sizeof(secured_message_opaque_element_supported_version_t) +
70 : 96 : sizeof(spdm_version_number_t) * version_count;
71 : : }
72 : : /* Add Padding*/
73 : 116 : return (size + 3) & ~3;
74 : : }
75 : :
76 : 570 : bool libspdm_get_element_from_opaque_data_with_element_id (libspdm_context_t *spdm_context,
77 : : size_t data_in_size, const void *data_in,
78 : : uint8_t element_id, uint8_t element_index,
79 : : uint8_t *total_matched_element_cnt,
80 : : const void **get_element_ptr, size_t *get_element_len)
81 : : {
82 : : const secured_message_general_opaque_data_table_header_t *general_opaque_data_table_header;
83 : : const spdm_general_opaque_data_table_header_t *spdm_general_opaque_data_table_header;
84 : : const opaque_element_table_header_t *opaque_element_table_header;
85 : : uint16_t opaque_element_data_len;
86 : :
87 : : bool result;
88 : : uint8_t element_num;
89 : : uint8_t index;
90 : : uint8_t matched_element_cnt;
91 : : size_t data_element_size;
92 : : size_t current_element_len;
93 : : size_t total_element_len;
94 : :
95 : : /*check parameter in*/
96 [ - + ]: 570 : if (element_id > SPDM_REGISTRY_ID_MAX) {
97 : 0 : return false;
98 : : }
99 [ + - - + ]: 570 : if ((data_in_size == 0) || (data_in == NULL)) {
100 : 0 : return false;
101 : : }
102 : :
103 [ + + ]: 570 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
104 : 180 : spdm_general_opaque_data_table_header = data_in;
105 [ - + ]: 180 : if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
106 : 0 : return false;
107 : : }
108 [ - + ]: 180 : if (spdm_general_opaque_data_table_header->total_elements < 1) {
109 : 0 : return false;
110 : : }
111 : 180 : opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
112 : :
113 : 180 : element_num = spdm_general_opaque_data_table_header->total_elements;
114 : :
115 : 180 : data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
116 : : } else {
117 : 390 : general_opaque_data_table_header = data_in;
118 [ - + ]: 390 : if (data_in_size < sizeof(secured_message_general_opaque_data_table_header_t)) {
119 : 0 : return false;
120 : : }
121 [ + + ]: 390 : if ((general_opaque_data_table_header->spec_id != SECURED_MESSAGE_OPAQUE_DATA_SPEC_ID) ||
122 [ + - ]: 388 : (general_opaque_data_table_header->opaque_version != SECURED_MESSAGE_OPAQUE_VERSION) ||
123 [ - + ]: 388 : (general_opaque_data_table_header->total_elements < 1)) {
124 : 2 : return false;
125 : : }
126 : 388 : opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
127 : :
128 : 388 : element_num = general_opaque_data_table_header->total_elements;
129 : :
130 : 388 : data_element_size = data_in_size -
131 : : sizeof(secured_message_general_opaque_data_table_header_t);
132 : : }
133 : :
134 : 568 : total_element_len = 0;
135 : 568 : result = false;
136 : :
137 : : /* find the Nth element with specific element_id, N = element_index. */
138 : 568 : matched_element_cnt = 0;
139 [ + + ]: 1446 : for (index = 0; index < element_num; index++) {
140 : : /*ensure the opaque_element_table_header is valid*/
141 [ - + ]: 888 : if (total_element_len + sizeof(opaque_element_table_header_t) >
142 : : data_element_size) {
143 : 0 : return false;
144 : : }
145 : :
146 : : /*check element header id*/
147 [ + + ]: 888 : if ((opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX)) {
148 : 8 : return false;
149 : : }
150 : :
151 : 880 : if ((total_element_len + sizeof(opaque_element_table_header_t) +
152 [ - + ]: 880 : opaque_element_table_header->vendor_len + 2) > data_element_size) {
153 : 0 : return false;
154 : : }
155 : :
156 : 880 : opaque_element_data_len = libspdm_read_uint16(
157 : 880 : (const uint8_t *)opaque_element_table_header + sizeof(opaque_element_table_header_t) +
158 : 880 : opaque_element_table_header->vendor_len);
159 : :
160 : 880 : current_element_len = sizeof(opaque_element_table_header_t) +
161 : 880 : opaque_element_table_header->vendor_len + 2 + opaque_element_data_len;
162 : : /* Add Padding*/
163 : 880 : current_element_len = (current_element_len + 3) & ~3;
164 : :
165 : 880 : total_element_len += current_element_len;
166 : :
167 [ + + ]: 880 : if (data_element_size < total_element_len) {
168 : 2 : return false;
169 : : }
170 : :
171 [ + + ]: 878 : if (opaque_element_table_header->id == element_id) {
172 : : /*get element by element id*/
173 [ + + ]: 644 : if (matched_element_cnt == element_index) {
174 : 566 : *get_element_ptr = opaque_element_table_header;
175 : 566 : *get_element_len = current_element_len;
176 : 566 : result = true;
177 : : }
178 : 644 : matched_element_cnt += 1;
179 : : }
180 : :
181 : : /*move to next element*/
182 : 878 : opaque_element_table_header = (const opaque_element_table_header_t *)
183 : : ((const uint8_t *)opaque_element_table_header +
184 : : current_element_len);
185 : : }
186 : :
187 : : /*ensure data size is right*/
188 [ - + ]: 558 : if (data_element_size != total_element_len) {
189 : 0 : return false;
190 : : }
191 : :
192 : 558 : *total_matched_element_cnt = matched_element_cnt;
193 : 558 : return result;
194 : : }
195 : :
196 : 280 : bool libspdm_get_sm_data_element_from_opaque_data (libspdm_context_t *spdm_context,
197 : : size_t data_in_size, const void *data_in,
198 : : uint8_t sm_data_id,
199 : : const void **get_element_ptr, size_t *get_element_len)
200 : : {
201 : : const opaque_element_table_header_t *opaque_element_table_header;
202 : : size_t opaque_element_len;
203 : : const secured_message_opaque_element_table_header_t *secured_message_element_table_header;
204 : : const secured_message_opaque_element_header_t *secured_message_element_header;
205 : : bool result;
206 : : uint8_t element_index;
207 : : uint8_t element_num;
208 : : uint8_t total_matched_element_cnt;
209 : :
210 : : /*check parameter in*/
211 [ + - - + ]: 280 : if ((data_in_size == 0) || (data_in == NULL)) {
212 : 0 : return false;
213 : : }
214 : :
215 : : /*get the total matched element count*/
216 : 280 : result = libspdm_get_element_from_opaque_data_with_element_id(
217 : : spdm_context, data_in_size, data_in,
218 : : SPDM_REGISTRY_ID_DMTF, 0, &total_matched_element_cnt,
219 : : (const void **) &opaque_element_table_header, &opaque_element_len);
220 [ + + ]: 280 : if (!result) {
221 : 12 : return false;
222 : : }
223 : :
224 : 268 : element_num = total_matched_element_cnt;
225 [ + + ]: 320 : for (element_index = 0; element_index < element_num; element_index++) {
226 : : /*get element by element id*/
227 : 290 : result = libspdm_get_element_from_opaque_data_with_element_id(
228 : : spdm_context, data_in_size, data_in,
229 : : SPDM_REGISTRY_ID_DMTF, element_index, &total_matched_element_cnt,
230 : : (const void **) &opaque_element_table_header, &opaque_element_len);
231 [ - + ]: 290 : if (!result) {
232 : 0 : return false;
233 : : }
234 : :
235 : 290 : secured_message_element_table_header = (const void *)opaque_element_table_header;
236 [ + - ]: 290 : if (secured_message_element_table_header->vendor_len == 0) {
237 : 290 : secured_message_element_header =
238 : : (const void *)(secured_message_element_table_header + 1);
239 : 290 : if ((const uint8_t *)secured_message_element_header +
240 : : sizeof(secured_message_opaque_element_header_t) >
241 [ - + ]: 290 : (const uint8_t *)data_in + data_in_size) {
242 : 0 : return false;
243 : : }
244 : :
245 [ + + ]: 290 : if ((secured_message_element_header->sm_data_id == sm_data_id) &&
246 [ + - ]: 238 : (secured_message_element_header->sm_data_version ==
247 : : SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION)) {
248 : 238 : *get_element_ptr = opaque_element_table_header;
249 : 238 : *get_element_len = opaque_element_len;
250 : 238 : return true;
251 : : }
252 : : }
253 : : }
254 : :
255 : 30 : return false;
256 : : }
257 : :
258 : 236 : bool libspdm_process_general_opaque_data_check(libspdm_context_t *spdm_context,
259 : : size_t data_in_size,
260 : : const void *data_in)
261 : : {
262 : : const spdm_general_opaque_data_table_header_t
263 : : *spdm_general_opaque_data_table_header;
264 : : const opaque_element_table_header_t
265 : : *opaque_element_table_header;
266 : : uint8_t element_num;
267 : : uint8_t element_index;
268 : : uint16_t opaque_element_data_len;
269 : : size_t data_element_size;
270 : : size_t current_element_len;
271 : : size_t total_element_len;
272 : 236 : uint8_t zero_padding[4] = {0};
273 : :
274 : 236 : total_element_len = 0;
275 : :
276 [ + + ]: 236 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
277 [ + + ]: 54 : if ((spdm_context->connection_info.algorithm.other_params_support &
278 : : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
279 : : /* Check byte alignment */
280 [ - + ]: 46 : if ((data_in_size & 3) != 0) {
281 : 0 : return false;
282 : : }
283 : :
284 : 46 : spdm_general_opaque_data_table_header = data_in;
285 [ - + ]: 46 : if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
286 : 0 : return false;
287 : : }
288 [ + + ]: 46 : if (spdm_general_opaque_data_table_header->total_elements < 1) {
289 : 2 : return false;
290 : : }
291 : 44 : opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
292 : :
293 : 44 : element_num = spdm_general_opaque_data_table_header->total_elements;
294 : :
295 : 44 : data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
296 : :
297 [ + + ]: 100 : for (element_index = 0; element_index < element_num; element_index++) {
298 : : /*ensure the opaque_element_table_header is valid*/
299 [ - + ]: 58 : if (total_element_len + sizeof(opaque_element_table_header_t) +
300 : : sizeof(opaque_element_data_len) >
301 : : data_element_size) {
302 : 0 : return false;
303 : : }
304 : :
305 : : /*check element header id*/
306 [ - + ]: 58 : if (opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX) {
307 : 0 : return false;
308 : : }
309 : :
310 : : /*ensure the vendor_id and opaque_element_data_len field are within the buffer*/
311 : 58 : if (total_element_len + sizeof(opaque_element_table_header_t) +
312 [ - + ]: 58 : opaque_element_table_header->vendor_len +
313 : : sizeof(opaque_element_data_len) >
314 : : data_element_size) {
315 : 0 : return false;
316 : : }
317 : :
318 : 58 : opaque_element_data_len = libspdm_read_uint16(
319 : 58 : (const uint8_t *)(opaque_element_table_header + 1) +
320 : 58 : opaque_element_table_header->vendor_len);
321 : :
322 : 58 : current_element_len = sizeof(opaque_element_table_header_t) +
323 : 58 : opaque_element_table_header->vendor_len +
324 : 58 : sizeof(opaque_element_data_len) +
325 : : opaque_element_data_len;
326 : :
327 : : /*ensure the element with padding is within the buffer before reading it*/
328 [ - + ]: 58 : if (total_element_len + ((current_element_len + 3) & ~3) >
329 : : data_element_size) {
330 : 0 : return false;
331 : : }
332 : :
333 [ + + ]: 58 : if ((current_element_len & 3) != 0) {
334 [ + + ]: 30 : if (!libspdm_consttime_is_mem_equal(zero_padding,
335 : : (uint8_t *)(size_t)
336 : : (opaque_element_table_header) +
337 : : current_element_len,
338 : 30 : 4 - (current_element_len & 3))) {
339 : 2 : return false;
340 : : }
341 : : }
342 : : /* Add Padding*/
343 : 56 : current_element_len = (current_element_len + 3) & ~3;
344 : :
345 : 56 : total_element_len += current_element_len;
346 : :
347 : : /*move to next element*/
348 : 56 : opaque_element_table_header =
349 : : (const opaque_element_table_header_t *)
350 : : ((const uint8_t *)opaque_element_table_header +
351 : : current_element_len);
352 : : }
353 : : }
354 : : }
355 : :
356 : 232 : return true;
357 : : }
358 : :
359 : : /**
360 : : * Process opaque data version selection.
361 : : *
362 : : * This function should be called in KEY_EXCHANGE/PSK_EXCHANGE response parsing in requester.
363 : : *
364 : : * @param data_in_size size in bytes of the data_in.
365 : : * @param data_in A pointer to the buffer to store the opaque data version selection.
366 : : **/
367 : 110 : libspdm_return_t libspdm_process_opaque_data_version_selection_data(
368 : : libspdm_context_t *spdm_context, size_t data_in_size, void *data_in,
369 : : spdm_version_number_t *secured_message_version)
370 : : {
371 : : const secured_message_opaque_element_table_header_t *opaque_element_table_header;
372 : : const secured_message_opaque_element_version_selection_t *opaque_element_version_section;
373 : :
374 : : bool result;
375 : : uint8_t secured_message_version_index;
376 : : const void *get_element_ptr;
377 : : size_t get_element_len;
378 : :
379 : 110 : result = false;
380 : 110 : get_element_ptr = NULL;
381 : :
382 [ - + ]: 110 : if (spdm_context->local_context.secured_message_version.secured_message_version_count == 0) {
383 : 0 : return LIBSPDM_STATUS_SUCCESS;
384 : : }
385 : :
386 : 110 : result = libspdm_get_sm_data_element_from_opaque_data(
387 : : spdm_context, data_in_size, data_in,
388 : : SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_ID_VERSION_SELECTION,
389 : : &get_element_ptr, &get_element_len);
390 [ + + - + ]: 110 : if ((!result) || (get_element_ptr == NULL)) {
391 : 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"get element error!\n"));
392 : 6 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
393 : : }
394 : :
395 : 104 : opaque_element_table_header = (const secured_message_opaque_element_table_header_t*)
396 : : get_element_ptr;
397 : :
398 : : /* Check for selection version data. */
399 [ + - ]: 104 : if ((opaque_element_table_header->vendor_len != 0) ||
400 [ - + ]: 104 : (opaque_element_table_header->opaque_element_data_len !=
401 : : sizeof(secured_message_opaque_element_version_selection_t))) {
402 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
403 : : }
404 : 104 : opaque_element_version_section = (const void *)(opaque_element_table_header + 1);
405 : :
406 : 104 : if ((const uint8_t *)opaque_element_version_section +
407 : : sizeof(secured_message_opaque_element_version_selection_t) >
408 [ - + ]: 104 : (const uint8_t *)opaque_element_table_header + get_element_len) {
409 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
410 : : }
411 : :
412 : 104 : for (secured_message_version_index = 0;
413 : 128 : secured_message_version_index <
414 [ + - ]: 128 : spdm_context->local_context.secured_message_version.secured_message_version_count;
415 : 24 : secured_message_version_index++) {
416 [ + + ]: 256 : if (libspdm_get_version_from_version_number(opaque_element_version_section->
417 : : selected_version)
418 : : ==
419 : 128 : libspdm_get_version_from_version_number(
420 : 128 : spdm_context->local_context.secured_message_version.secured_message_version[
421 : : secured_message_version_index])) {
422 : 104 : libspdm_copy_mem(secured_message_version,
423 : : sizeof(spdm_version_number_t),
424 : 104 : &(opaque_element_version_section->selected_version),
425 : : sizeof(spdm_version_number_t));
426 : 104 : return LIBSPDM_STATUS_SUCCESS;
427 : : }
428 : : }
429 : :
430 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
431 : : }
432 : :
433 : : /* Return the highest secured message version this endpoint offers in its local supported list, in
434 : : * version-number form (e.g. SECURED_SPDM_VERSION_13 << SPDM_VERSION_NUMBER_SHIFT_BIT), or 0 if the
435 : : * list is empty. The Requester uses this as the "version" to gate the AEADlimitOE element in its
436 : : * request, since no version has been negotiated yet at that point. */
437 : 312 : spdm_version_number_t libspdm_local_max_secured_message_version(
438 : : const libspdm_context_t *spdm_context)
439 : : {
440 : : uint8_t index;
441 : : spdm_version_number_t max_version;
442 : :
443 : 312 : max_version = 0;
444 : 312 : for (index = 0;
445 [ + + ]: 672 : index < spdm_context->local_context.secured_message_version.secured_message_version_count;
446 : 360 : index++) {
447 : 360 : spdm_version_number_t version =
448 : 360 : spdm_context->local_context.secured_message_version.secured_message_version[index];
449 [ + - ]: 720 : if (libspdm_get_version_from_version_number(version) >
450 : 360 : libspdm_get_version_from_version_number(max_version)) {
451 : 360 : max_version = version;
452 : : }
453 : : }
454 : 312 : return max_version;
455 : : }
456 : :
457 : : /* DSP0277 1.3: derive the AeadLimitExponent that this endpoint advertises from its single source of
458 : : * truth, max_spdm_session_sequence_number. That value is the maximum sequence number that IS allowed
459 : : * (seq > max triggers overflow), i.e. AeadLimit - 1, so the AEAD limit is
460 : : * AeadLimit = max + 1 = 2 ^ exponent (see libspdm_apply_aead_limit_to_session). The advertised
461 : : * exponent is therefore floor(log2(max + 1)): the largest e such that 2 ^ e <= max + 1. The all-ones
462 : : * cap maps to 64 (the spec default, since 2^64 is not representable). A cap that is not of the form
463 : : * 2 ^ e - 1 rounds the exponent down to the nearest representable AEAD limit, which is <= the
464 : : * configured cap (the safe direction). */
465 : 104 : static uint8_t libspdm_aead_limit_exponent_from_max_sequence_number(uint64_t max_sequence_number)
466 : : {
467 : : uint8_t exponent;
468 : : uint64_t aead_limit;
469 : :
470 : : /* All-ones is the maximum allowed value for the default AeadLimit of 2^64, which is not
471 : : * representable in a uint64_t; adding 1 would overflow, so handle it directly. */
472 [ + + ]: 104 : if (max_sequence_number >= LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER) {
473 : 86 : return SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_MAX;
474 : : }
475 : :
476 : 18 : aead_limit = max_sequence_number + 1;
477 : 18 : exponent = 0;
478 [ + + ]: 460 : while (aead_limit > 1) {
479 : 442 : aead_limit >>= 1;
480 : 442 : exponent++;
481 : : }
482 : 18 : return exponent;
483 : : }
484 : :
485 : 822 : size_t libspdm_get_opaque_data_aead_limit_element_size(const libspdm_context_t *spdm_context,
486 : : spdm_version_number_t secured_message_version)
487 : : {
488 : : size_t size;
489 : :
490 : : /* The AEADlimitOE element is only defined for secured message version 1.3 and later. It must
491 : : * not be appended to opaque data for an older version. */
492 [ + + ]: 822 : if (libspdm_get_version_from_version_number(secured_message_version) < SECURED_SPDM_VERSION_13) {
493 : 706 : return 0;
494 : : }
495 : :
496 : 116 : size = sizeof(secured_message_opaque_element_table_header_t) +
497 : : sizeof(secured_message_opaque_element_aead_limit_t);
498 : : /* Add Padding*/
499 : 116 : return (size + 3) & ~3;
500 : : }
501 : :
502 : : /* Walk a well-formed opaque data blob (general opaque data table header followed by total_elements
503 : : * elements) and return its current length in bytes. data_out_capacity bounds the walk. Returns
504 : : * false if the blob does not fit within data_out_capacity. */
505 : 396 : static bool libspdm_get_opaque_data_current_size(libspdm_context_t *spdm_context,
506 : : const void *data_out, size_t data_out_capacity,
507 : : size_t *current_size)
508 : : {
509 : : const secured_message_general_opaque_data_table_header_t *general_opaque_data_table_header;
510 : : const spdm_general_opaque_data_table_header_t *spdm_general_opaque_data_table_header;
511 : : const opaque_element_table_header_t *opaque_element_table_header;
512 : : uint8_t element_num;
513 : : uint8_t index;
514 : : uint16_t opaque_element_data_len;
515 : : size_t total_size;
516 : : size_t current_element_len;
517 : :
518 [ + + ]: 396 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
519 [ - + ]: 50 : if (data_out_capacity < sizeof(spdm_general_opaque_data_table_header_t)) {
520 : 0 : return false;
521 : : }
522 : 50 : spdm_general_opaque_data_table_header = data_out;
523 : 50 : element_num = spdm_general_opaque_data_table_header->total_elements;
524 : 50 : opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
525 : 50 : total_size = sizeof(spdm_general_opaque_data_table_header_t);
526 : : } else {
527 [ - + ]: 346 : if (data_out_capacity < sizeof(secured_message_general_opaque_data_table_header_t)) {
528 : 0 : return false;
529 : : }
530 : 346 : general_opaque_data_table_header = data_out;
531 : 346 : element_num = general_opaque_data_table_header->total_elements;
532 : 346 : opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
533 : 346 : total_size = sizeof(secured_message_general_opaque_data_table_header_t);
534 : : }
535 : :
536 [ + + ]: 792 : for (index = 0; index < element_num; index++) {
537 : 396 : if (total_size + sizeof(opaque_element_table_header_t) +
538 [ - + ]: 396 : opaque_element_table_header->vendor_len + sizeof(uint16_t) > data_out_capacity) {
539 : 0 : return false;
540 : : }
541 : 396 : opaque_element_data_len = libspdm_read_uint16(
542 : 396 : (const uint8_t *)opaque_element_table_header + sizeof(opaque_element_table_header_t) +
543 : 396 : opaque_element_table_header->vendor_len);
544 : 396 : current_element_len = sizeof(opaque_element_table_header_t) +
545 : 396 : opaque_element_table_header->vendor_len + sizeof(uint16_t) +
546 : : opaque_element_data_len;
547 : : /* Add Padding*/
548 : 396 : current_element_len = (current_element_len + 3) & ~3;
549 [ - + ]: 396 : if (total_size + current_element_len > data_out_capacity) {
550 : 0 : return false;
551 : : }
552 : 396 : total_size += current_element_len;
553 : 396 : opaque_element_table_header = (const opaque_element_table_header_t *)
554 : : ((const uint8_t *)opaque_element_table_header +
555 : : current_element_len);
556 : : }
557 : :
558 : 396 : *current_size = total_size;
559 : 396 : return true;
560 : : }
561 : :
562 : 396 : void libspdm_build_opaque_data_aead_limit_element(libspdm_context_t *spdm_context,
563 : : spdm_version_number_t secured_message_version,
564 : : size_t *data_out_size, void *data_out)
565 : : {
566 : : size_t data_out_capacity;
567 : : size_t existing_size;
568 : : size_t element_size;
569 : : secured_message_opaque_element_table_header_t *opaque_element_table_header;
570 : : secured_message_opaque_element_aead_limit_t *opaque_element_aead_limit;
571 : : uint8_t *element_ptr;
572 : : bool result;
573 : :
574 : : /* data_out already holds a blob built by the supported-version / version-selection builder.
575 : : * *data_out_size is the capacity of data_out on input. Parse the blob to find where it ends;
576 : : * that is the append offset. */
577 : 396 : data_out_capacity = *data_out_size;
578 : 396 : result = libspdm_get_opaque_data_current_size(spdm_context, data_out, data_out_capacity,
579 : : &existing_size);
580 : 396 : LIBSPDM_ASSERT(result);
581 [ - + ]: 396 : if (!result) {
582 : 336 : return;
583 : : }
584 : :
585 : : /* The size helper enforces the secured message version 1.3 gate; for an older version it
586 : : * returns 0 and nothing is appended. */
587 : 396 : element_size = libspdm_get_opaque_data_aead_limit_element_size(spdm_context,
588 : : secured_message_version);
589 [ + + ]: 396 : if (element_size == 0) {
590 : 336 : *data_out_size = existing_size;
591 : 336 : return;
592 : : }
593 : :
594 : 60 : LIBSPDM_ASSERT(existing_size + element_size <= data_out_capacity);
595 : :
596 [ + + ]: 60 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
597 : : spdm_general_opaque_data_table_header_t *spdm_general_opaque_data_table_header;
598 : 30 : spdm_general_opaque_data_table_header = data_out;
599 : 30 : spdm_general_opaque_data_table_header->total_elements++;
600 : : } else {
601 : : secured_message_general_opaque_data_table_header_t *general_opaque_data_table_header;
602 : 30 : general_opaque_data_table_header = data_out;
603 : 30 : general_opaque_data_table_header->total_elements++;
604 : : }
605 : :
606 : 60 : element_ptr = (uint8_t *)data_out + existing_size;
607 : 60 : opaque_element_table_header = (void *)element_ptr;
608 : 60 : opaque_element_table_header->id = SPDM_REGISTRY_ID_DMTF;
609 : 60 : opaque_element_table_header->vendor_len = 0;
610 : 60 : opaque_element_table_header->opaque_element_data_len =
611 : : sizeof(secured_message_opaque_element_aead_limit_t);
612 : :
613 : 60 : opaque_element_aead_limit = (void *)(opaque_element_table_header + 1);
614 : 60 : opaque_element_aead_limit->sm_data_version =
615 : : SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION;
616 : 60 : opaque_element_aead_limit->sm_data_id =
617 : : SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_ID_AEAD_LIMIT;
618 : 60 : opaque_element_aead_limit->aead_limit_exponent =
619 : 60 : libspdm_aead_limit_exponent_from_max_sequence_number(
620 : : spdm_context->max_spdm_session_sequence_number);
621 : :
622 : : /* Zero the padding bytes between the element and the new end. */
623 : 60 : libspdm_zero_mem(element_ptr + sizeof(secured_message_opaque_element_table_header_t) +
624 : : sizeof(secured_message_opaque_element_aead_limit_t),
625 : : element_size - (sizeof(secured_message_opaque_element_table_header_t) +
626 : : sizeof(secured_message_opaque_element_aead_limit_t)));
627 : :
628 : 60 : *data_out_size = existing_size + element_size;
629 : : }
630 : :
631 : 222 : libspdm_return_t libspdm_process_opaque_data_aead_limit(libspdm_context_t *spdm_context,
632 : : spdm_version_number_t
633 : : secured_message_version,
634 : : size_t data_in_size, const void *data_in,
635 : : uint8_t *aead_limit_exponent)
636 : : {
637 : : bool result;
638 : : const void *get_element_ptr;
639 : : size_t get_element_len;
640 : : const secured_message_opaque_element_table_header_t *opaque_element_table_header;
641 : : const secured_message_opaque_element_aead_limit_t *opaque_element_aead_limit;
642 : :
643 : : /* Default per DSP0277 1.3: when the AEAD limit element is absent, the exponent is 64. */
644 : 222 : *aead_limit_exponent = SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_DEFAULT;
645 : :
646 : : /* The AEADlimitOE element is only defined for secured message version 1.3 and later. For an
647 : : * older negotiated version, ignore the element entirely (keep the default exponent) even if a
648 : : * peer erroneously included it. */
649 [ + + ]: 222 : if (libspdm_get_version_from_version_number(secured_message_version) <
650 : : SECURED_SPDM_VERSION_13) {
651 : 172 : return LIBSPDM_STATUS_SUCCESS;
652 : : }
653 : :
654 : 50 : get_element_ptr = NULL;
655 : 50 : result = libspdm_get_sm_data_element_from_opaque_data(
656 : : spdm_context, data_in_size, data_in,
657 : : SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_ID_AEAD_LIMIT,
658 : : &get_element_ptr, &get_element_len);
659 [ + + - + ]: 50 : if ((!result) || (get_element_ptr == NULL)) {
660 : : /* Absent is allowed: keep the default exponent. */
661 : 30 : return LIBSPDM_STATUS_SUCCESS;
662 : : }
663 : :
664 : 20 : opaque_element_table_header = (const secured_message_opaque_element_table_header_t *)
665 : : get_element_ptr;
666 [ + - ]: 20 : if ((opaque_element_table_header->vendor_len != 0) ||
667 [ - + ]: 20 : (opaque_element_table_header->opaque_element_data_len !=
668 : : sizeof(secured_message_opaque_element_aead_limit_t))) {
669 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
670 : : }
671 : :
672 : 20 : opaque_element_aead_limit = (const void *)(opaque_element_table_header + 1);
673 : 20 : if ((const uint8_t *)opaque_element_aead_limit +
674 : : sizeof(secured_message_opaque_element_aead_limit_t) >
675 [ - + ]: 20 : (const uint8_t *)opaque_element_table_header + get_element_len) {
676 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
677 : : }
678 : :
679 : : /* AeadLimitExponent shall be <= 64. */
680 [ + + ]: 20 : if (opaque_element_aead_limit->aead_limit_exponent >
681 : : SECURED_MESSAGE_AEAD_LIMIT_EXPONENT_MAX) {
682 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
683 : : }
684 : :
685 : 18 : *aead_limit_exponent = opaque_element_aead_limit->aead_limit_exponent;
686 : 18 : return LIBSPDM_STATUS_SUCCESS;
687 : : }
688 : :
689 : 44 : void libspdm_apply_aead_limit_to_session(libspdm_context_t *spdm_context,
690 : : void *session_info_p,
691 : : uint8_t peer_aead_limit_exponent)
692 : : {
693 : : libspdm_session_info_t *session_info;
694 : : uint8_t local_aead_limit_exponent;
695 : : uint64_t local_max_sequence_number;
696 : : uint64_t peer_max_sequence_number;
697 : : uint64_t effective_max;
698 : :
699 : 44 : session_info = session_info_p;
700 : :
701 : : /* The caller invokes this only when the session negotiated secured message version >= 1.3.
702 : : *
703 : : * The DSP0277 AeadLimit is the first sequence number that is NOT allowed, so the maximum
704 : : * allowed sequence number is AeadLimit - 1 = 2 ^ AeadLimitExponent - 1. Fold together this
705 : : * endpoint's advertised limit and the peer's advertised limit; the effective cap is the
706 : : * smaller of the two, so neither side's limit is ever raised by the other.
707 : : *
708 : : * This endpoint's contribution must be the SAME rounded-down limit it advertised on the wire,
709 : : * not the raw configured max_spdm_session_sequence_number. When the configured cap is not of
710 : : * the form 2 ^ e - 1 the advertised exponent is floor(log2(cap + 1)); enforcing the raw cap
711 : : * here would let this side send past the limit the peer derives from that exponent. At
712 : : * exponent 64 the maximum allowed value is 2^64 - 1, i.e. LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER
713 : : * (all-ones), which is also the default. */
714 : 44 : local_aead_limit_exponent = libspdm_aead_limit_exponent_from_max_sequence_number(
715 : : spdm_context->max_spdm_session_sequence_number);
716 [ + + ]: 44 : if (local_aead_limit_exponent >= 64) {
717 : 36 : local_max_sequence_number = LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER;
718 : : } else {
719 : 8 : local_max_sequence_number = ((uint64_t)1 << local_aead_limit_exponent) - 1;
720 : : }
721 : :
722 [ + + ]: 44 : if (peer_aead_limit_exponent >= 64) {
723 : 32 : peer_max_sequence_number = LIBSPDM_MAX_SPDM_SESSION_SEQUENCE_NUMBER;
724 : : } else {
725 : 12 : peer_max_sequence_number = ((uint64_t)1 << peer_aead_limit_exponent) - 1;
726 : : }
727 : :
728 : 44 : effective_max = local_max_sequence_number;
729 [ + + ]: 44 : if (peer_max_sequence_number < effective_max) {
730 : 8 : effective_max = peer_max_sequence_number;
731 : : }
732 : :
733 : 44 : libspdm_secured_message_set_max_spdm_session_sequence_number(
734 : : session_info->secured_message_context, effective_max);
735 : 44 : }
|