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