Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2025 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 :
9 : /**
10 : * Return the size in bytes of opaque data version selection.
11 : *
12 : * This function should be called in KEY_EXCHANGE/PSK_EXCHANGE response generation.
13 : *
14 : * @return the size in bytes of opaque data version selection.
15 : **/
16 171 : size_t libspdm_get_opaque_data_version_selection_data_size(const libspdm_context_t *spdm_context)
17 : {
18 : size_t size;
19 :
20 171 : if (spdm_context->local_context.secured_message_version.spdm_version_count == 0) {
21 0 : return 0;
22 : }
23 :
24 171 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
25 21 : size = sizeof(spdm_general_opaque_data_table_header_t) +
26 : sizeof(secured_message_opaque_element_table_header_t) +
27 : sizeof(secured_message_opaque_element_version_selection_t);
28 : } else {
29 150 : size = sizeof(secured_message_general_opaque_data_table_header_t) +
30 : sizeof(secured_message_opaque_element_table_header_t) +
31 : sizeof(secured_message_opaque_element_version_selection_t);
32 : }
33 : /* Add Padding*/
34 171 : return (size + 3) & ~3;
35 : }
36 :
37 : /**
38 : * Return the size in bytes of opaque data supported version.
39 : *
40 : * This function should be called in KEY_EXCHANGE/PSK_EXCHANGE request generation.
41 : *
42 : * @return the size in bytes of opaque data supported version.
43 : **/
44 344 : size_t libspdm_get_opaque_data_supported_version_data_size(libspdm_context_t *spdm_context)
45 : {
46 : size_t size;
47 :
48 344 : if (spdm_context->local_context.secured_message_version.spdm_version_count == 0) {
49 0 : return 0;
50 : }
51 :
52 344 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
53 24 : size = sizeof(spdm_general_opaque_data_table_header_t) +
54 : sizeof(secured_message_opaque_element_table_header_t) +
55 : sizeof(secured_message_opaque_element_supported_version_t) +
56 24 : sizeof(spdm_version_number_t) *
57 24 : spdm_context->local_context.secured_message_version.spdm_version_count;
58 : } else {
59 320 : size = sizeof(secured_message_general_opaque_data_table_header_t) +
60 : sizeof(secured_message_opaque_element_table_header_t) +
61 : sizeof(secured_message_opaque_element_supported_version_t) +
62 320 : sizeof(spdm_version_number_t) *
63 320 : spdm_context->local_context.secured_message_version.spdm_version_count;
64 : }
65 : /* Add Padding*/
66 344 : return (size + 3) & ~3;
67 : }
68 :
69 : /**
70 : * Return the size in bytes of opaque data supported version.
71 : *
72 : * This function should be called in libspdm_process_opaque_data_supported_version_data.
73 : *
74 : * @param version_count Secure version count.
75 : *
76 : * @return the size in bytes of opaque data supported version.
77 : **/
78 26 : size_t libspdm_get_untrusted_opaque_data_supported_version_data_size(
79 : libspdm_context_t *spdm_context, uint8_t version_count)
80 : {
81 : size_t size;
82 :
83 26 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
84 8 : size = sizeof(spdm_general_opaque_data_table_header_t) +
85 : sizeof(secured_message_opaque_element_table_header_t) +
86 : sizeof(secured_message_opaque_element_supported_version_t) +
87 8 : sizeof(spdm_version_number_t) * version_count;
88 : } else {
89 18 : size = sizeof(secured_message_general_opaque_data_table_header_t) +
90 : sizeof(secured_message_opaque_element_table_header_t) +
91 : sizeof(secured_message_opaque_element_supported_version_t) +
92 18 : sizeof(spdm_version_number_t) * version_count;
93 : }
94 : /* Add Padding*/
95 26 : return (size + 3) & ~3;
96 : }
97 :
98 : /**
99 : * Get element from multi element opaque data by element id.
100 : *
101 : * This function should be called in
102 : * libspdm_process_opaque_data_supported_version_data/libspdm_process_opaque_data_version_selection_data.
103 : *
104 : * @param[in] data_in_size size of multi element opaque data.
105 : * @param[in] data_in A pointer to the multi element opaque data.
106 : * @param[in] element_id element id.
107 : * @param[in] sm_data_id sm_data_id to identify for the Secured Message data type.
108 : * @param[out] get_element_ptr pointer to store found element
109 : *
110 : * @retval true get element successfully
111 : * @retval false get element failed
112 : **/
113 69 : bool libspdm_get_element_from_opaque_data(libspdm_context_t *spdm_context,
114 : size_t data_in_size, const void *data_in,
115 : uint8_t element_id, uint8_t sm_data_id,
116 : const void **get_element_ptr, size_t *get_element_len)
117 : {
118 : const secured_message_general_opaque_data_table_header_t *general_opaque_data_table_header;
119 : const spdm_general_opaque_data_table_header_t *spdm_general_opaque_data_table_header;
120 : const opaque_element_table_header_t *opaque_element_table_header;
121 : uint16_t opaque_element_data_len;
122 : const secured_message_opaque_element_table_header_t *secured_message_element_table_header;
123 : const secured_message_opaque_element_header_t *secured_message_element_header;
124 :
125 : bool result;
126 : uint8_t element_num;
127 : uint8_t element_index;
128 : size_t data_element_size;
129 : size_t current_element_len;
130 : size_t total_element_len;
131 :
132 : /*check parameter in*/
133 69 : if (element_id > SPDM_REGISTRY_ID_MAX) {
134 0 : return false;
135 : }
136 69 : if ((data_in_size == 0) || (data_in == NULL)) {
137 0 : return false;
138 : }
139 :
140 69 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
141 17 : spdm_general_opaque_data_table_header = data_in;
142 17 : if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
143 0 : return false;
144 : }
145 17 : if (spdm_general_opaque_data_table_header->total_elements < 1) {
146 0 : return false;
147 : }
148 17 : opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
149 :
150 17 : element_num = spdm_general_opaque_data_table_header->total_elements;
151 :
152 17 : data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
153 : } else {
154 52 : general_opaque_data_table_header = data_in;
155 52 : if (data_in_size < sizeof(secured_message_general_opaque_data_table_header_t)) {
156 0 : return false;
157 : }
158 52 : if ((general_opaque_data_table_header->spec_id != SECURED_MESSAGE_OPAQUE_DATA_SPEC_ID) ||
159 51 : (general_opaque_data_table_header->opaque_version != SECURED_MESSAGE_OPAQUE_VERSION) ||
160 51 : (general_opaque_data_table_header->total_elements < 1)) {
161 1 : return false;
162 : }
163 51 : opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
164 :
165 51 : element_num = general_opaque_data_table_header->total_elements;
166 :
167 51 : data_element_size = data_in_size -
168 : sizeof(secured_message_general_opaque_data_table_header_t);
169 : }
170 :
171 68 : total_element_len = 0;
172 68 : result = false;
173 :
174 208 : for (element_index = 0; element_index < element_num; element_index++) {
175 : /*ensure the opaque_element_table_header is valid*/
176 144 : if (total_element_len + sizeof(opaque_element_table_header_t) >
177 : data_element_size) {
178 0 : return false;
179 : }
180 :
181 : /*check element header id*/
182 144 : if ((opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX)) {
183 4 : return false;
184 : }
185 :
186 140 : if ((total_element_len + sizeof(opaque_element_table_header_t) +
187 140 : opaque_element_table_header->vendor_len + 2) > data_element_size) {
188 0 : return false;
189 : }
190 :
191 140 : opaque_element_data_len = libspdm_read_uint16(
192 140 : (const uint8_t *)opaque_element_table_header + sizeof(opaque_element_table_header_t) +
193 140 : opaque_element_table_header->vendor_len);
194 :
195 140 : current_element_len = sizeof(opaque_element_table_header_t) +
196 140 : opaque_element_table_header->vendor_len + 2 + opaque_element_data_len;
197 : /* Add Padding*/
198 140 : current_element_len = (current_element_len + 3) & ~3;
199 :
200 140 : total_element_len += current_element_len;
201 :
202 140 : if (data_element_size < total_element_len) {
203 0 : return false;
204 : }
205 :
206 140 : if (opaque_element_table_header->id == element_id) {
207 70 : secured_message_element_table_header = (const void *)opaque_element_table_header;
208 70 : if (secured_message_element_table_header->vendor_len == 0) {
209 70 : secured_message_element_header =
210 : (const void *)(secured_message_element_table_header + 1);
211 70 : if ((const uint8_t *)secured_message_element_header +
212 : sizeof(secured_message_opaque_element_header_t) >
213 70 : (const uint8_t *)data_in + data_in_size) {
214 0 : return false;
215 : }
216 :
217 70 : if ((secured_message_element_header->sm_data_id == sm_data_id) &&
218 68 : (secured_message_element_header->sm_data_version ==
219 : SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION)) {
220 : /*get element by element id*/
221 68 : *get_element_ptr = opaque_element_table_header;
222 68 : *get_element_len = current_element_len;
223 68 : result = true;
224 : }
225 : }
226 : }
227 :
228 : /*move to next element*/
229 140 : opaque_element_table_header = (const opaque_element_table_header_t *)
230 : ((const uint8_t *)opaque_element_table_header +
231 : current_element_len);
232 : }
233 :
234 : /*ensure data size is right*/
235 64 : if (data_element_size != total_element_len) {
236 0 : return false;
237 : }
238 :
239 64 : return result;
240 : }
241 :
242 : /**
243 : * Process general opaque data check
244 : *
245 : * @param data_in_size size in bytes of the data_in.
246 : * @param data_in A pointer to the buffer to store the opaque data version selection.
247 : *
248 : * @retval true check opaque data successfully
249 : * @retval false check opaque data failed
250 : **/
251 78 : bool libspdm_process_general_opaque_data_check(libspdm_context_t *spdm_context,
252 : size_t data_in_size,
253 : const void *data_in)
254 : {
255 : const spdm_general_opaque_data_table_header_t
256 : *spdm_general_opaque_data_table_header;
257 : const opaque_element_table_header_t
258 : *opaque_element_table_header;
259 : uint8_t element_num;
260 : uint8_t element_index;
261 : uint16_t opaque_element_data_len;
262 : size_t data_element_size;
263 : size_t current_element_len;
264 : size_t total_element_len;
265 78 : uint8_t zero_padding[4] = {0};
266 :
267 78 : total_element_len = 0;
268 :
269 78 : LIBSPDM_ASSERT(data_in_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
270 :
271 78 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
272 19 : if ((spdm_context->connection_info.algorithm.other_params_support &
273 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
274 : /* Check byte alignment */
275 15 : if ((data_in_size & 3) != 0) {
276 0 : return false;
277 : }
278 :
279 15 : spdm_general_opaque_data_table_header = data_in;
280 15 : if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
281 0 : return false;
282 : }
283 15 : if (spdm_general_opaque_data_table_header->total_elements < 1) {
284 0 : return false;
285 : }
286 15 : opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
287 :
288 15 : element_num = spdm_general_opaque_data_table_header->total_elements;
289 :
290 15 : data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
291 :
292 33 : for (element_index = 0; element_index < element_num; element_index++) {
293 : /*ensure the opaque_element_table_header is valid*/
294 19 : if (total_element_len + sizeof(opaque_element_table_header_t) +
295 : sizeof(opaque_element_data_len) >
296 : data_element_size) {
297 0 : return false;
298 : }
299 :
300 : /*check element header id*/
301 19 : if (opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX) {
302 0 : return false;
303 : }
304 :
305 19 : opaque_element_data_len = *(uint16_t *)((size_t)(opaque_element_table_header + 1) +
306 19 : opaque_element_table_header->vendor_len);
307 :
308 19 : current_element_len = sizeof(opaque_element_table_header_t) +
309 19 : opaque_element_table_header->vendor_len +
310 19 : sizeof(opaque_element_data_len) +
311 : opaque_element_data_len;
312 :
313 19 : if ((current_element_len & 3) != 0) {
314 13 : if (!libspdm_consttime_is_mem_equal(zero_padding,
315 : (uint8_t *)(size_t)
316 : (opaque_element_table_header) +
317 : current_element_len,
318 13 : 4 - (current_element_len & 3))) {
319 1 : return false;
320 : }
321 : }
322 : /* Add Padding*/
323 18 : current_element_len = (current_element_len + 3) & ~3;
324 :
325 18 : total_element_len += current_element_len;
326 :
327 18 : if (total_element_len > data_element_size) {
328 0 : return false;
329 : }
330 :
331 : /*move to next element*/
332 18 : opaque_element_table_header =
333 : (const opaque_element_table_header_t *)
334 : ((const uint8_t *)opaque_element_table_header +
335 : current_element_len);
336 : }
337 : }
338 : }
339 :
340 77 : return true;
341 : }
|