Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2024 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 169 : size_t libspdm_get_opaque_data_version_selection_data_size(const libspdm_context_t *spdm_context)
17 : {
18 : size_t size;
19 :
20 169 : if (spdm_context->local_context.secured_message_version.spdm_version_count == 0) {
21 0 : return 0;
22 : }
23 :
24 169 : 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 148 : 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 169 : 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 342 : size_t libspdm_get_opaque_data_supported_version_data_size(libspdm_context_t *spdm_context)
45 : {
46 : size_t size;
47 :
48 342 : if (spdm_context->local_context.secured_message_version.spdm_version_count == 0) {
49 0 : return 0;
50 : }
51 :
52 342 : 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 318 : 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 318 : sizeof(spdm_version_number_t) *
63 318 : spdm_context->local_context.secured_message_version.spdm_version_count;
64 : }
65 : /* Add Padding*/
66 342 : 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 68 : 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
119 : *general_opaque_data_table_header;
120 : const spdm_general_opaque_data_table_header_t
121 : *spdm_general_opaque_data_table_header;
122 : const opaque_element_table_header_t
123 : *opaque_element_table_header;
124 : uint16_t opaque_element_data_len;
125 : const secured_message_opaque_element_table_header_t
126 : *secured_message_element_table_header;
127 : const secured_message_opaque_element_header_t
128 : *secured_message_element_header;
129 :
130 : bool result;
131 : uint8_t element_num;
132 : uint8_t element_index;
133 : size_t data_element_size;
134 : size_t current_element_len;
135 : size_t total_element_len;
136 :
137 68 : total_element_len = 0;
138 68 : result = false;
139 :
140 : /*check parameter in*/
141 68 : if (element_id > SPDM_REGISTRY_ID_MAX) {
142 0 : return false;
143 : }
144 68 : if ((data_in_size == 0) || (data_in == NULL)) {
145 0 : return false;
146 : }
147 :
148 68 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_12) {
149 17 : spdm_general_opaque_data_table_header = data_in;
150 17 : if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
151 0 : return false;
152 : }
153 17 : if (spdm_general_opaque_data_table_header->total_elements < 1) {
154 0 : return false;
155 : }
156 17 : opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
157 :
158 17 : element_num = spdm_general_opaque_data_table_header->total_elements;
159 :
160 17 : data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
161 : } else {
162 51 : general_opaque_data_table_header = data_in;
163 51 : if (data_in_size < sizeof(secured_message_general_opaque_data_table_header_t)) {
164 0 : return false;
165 : }
166 51 : if ((general_opaque_data_table_header->spec_id !=
167 50 : SECURED_MESSAGE_OPAQUE_DATA_SPEC_ID) ||
168 50 : (general_opaque_data_table_header->opaque_version !=
169 50 : SECURED_MESSAGE_OPAQUE_VERSION) ||
170 50 : (general_opaque_data_table_header->total_elements < 1)) {
171 1 : return false;
172 : }
173 50 : opaque_element_table_header = (const void *)(general_opaque_data_table_header + 1);
174 :
175 50 : element_num = general_opaque_data_table_header->total_elements;
176 :
177 50 : data_element_size = data_in_size -
178 : sizeof(secured_message_general_opaque_data_table_header_t);
179 : }
180 :
181 200 : for (element_index = 0; element_index < element_num; element_index++) {
182 : /*ensure the opaque_element_table_header is valid*/
183 137 : if (total_element_len + sizeof(opaque_element_table_header_t) >
184 : data_element_size) {
185 0 : return false;
186 : }
187 :
188 : /*check element header id*/
189 137 : if ((opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX)) {
190 4 : return false;
191 : }
192 :
193 133 : if (total_element_len + sizeof(opaque_element_table_header_t) +
194 133 : opaque_element_table_header->vendor_len + 2 >
195 : data_element_size) {
196 0 : return false;
197 : }
198 :
199 133 : opaque_element_data_len = libspdm_read_uint16(
200 : (const uint8_t *)opaque_element_table_header +
201 133 : sizeof(opaque_element_table_header_t) +
202 133 : opaque_element_table_header->vendor_len);
203 :
204 133 : current_element_len = sizeof(opaque_element_table_header_t) +
205 133 : opaque_element_table_header->vendor_len +
206 133 : 2 + opaque_element_data_len;
207 : /* Add Padding*/
208 133 : current_element_len = (current_element_len + 3) & ~3;
209 :
210 133 : total_element_len += current_element_len;
211 :
212 133 : if (data_element_size < total_element_len) {
213 0 : return false;
214 : }
215 :
216 133 : if (opaque_element_table_header->id == element_id) {
217 69 : secured_message_element_table_header = (const void *)opaque_element_table_header;
218 69 : if (secured_message_element_table_header->vendor_len == 0) {
219 69 : secured_message_element_header =
220 : (const void *)(secured_message_element_table_header + 1);
221 69 : if ((const uint8_t *)secured_message_element_header +
222 : sizeof(secured_message_opaque_element_header_t) >
223 69 : (const uint8_t *)data_in + data_in_size) {
224 0 : return false;
225 : }
226 :
227 69 : if ((secured_message_element_header->sm_data_id == sm_data_id) &&
228 67 : (secured_message_element_header->sm_data_version ==
229 : SECURED_MESSAGE_OPAQUE_ELEMENT_SMDATA_DATA_VERSION)) {
230 : /*get element by element id*/
231 67 : *get_element_ptr = opaque_element_table_header;
232 67 : *get_element_len = current_element_len;
233 67 : result = true;
234 : }
235 : }
236 : }
237 :
238 : /*move to next element*/
239 133 : opaque_element_table_header = (const opaque_element_table_header_t *)
240 : ((const uint8_t *)opaque_element_table_header +
241 : current_element_len);
242 : }
243 :
244 : /*ensure data size is right*/
245 63 : if (data_element_size != total_element_len) {
246 0 : return false;
247 : }
248 :
249 63 : return result;
250 : }
251 :
252 : /**
253 : * Process general opaque data check
254 : *
255 : * @param data_in_size size in bytes of the data_in.
256 : * @param data_in A pointer to the buffer to store the opaque data version selection.
257 : *
258 : * @retval true check opaque data successfully
259 : * @retval false check opaque data failed
260 : **/
261 77 : bool libspdm_process_general_opaque_data_check(libspdm_context_t *spdm_context,
262 : size_t data_in_size,
263 : const void *data_in)
264 : {
265 : const spdm_general_opaque_data_table_header_t
266 : *spdm_general_opaque_data_table_header;
267 : const opaque_element_table_header_t
268 : *opaque_element_table_header;
269 : uint8_t element_num;
270 : uint8_t element_index;
271 : uint16_t opaque_element_data_len;
272 : size_t data_element_size;
273 : size_t current_element_len;
274 : size_t total_element_len;
275 77 : uint8_t zero_padding[4] = {0};
276 :
277 77 : total_element_len = 0;
278 :
279 77 : LIBSPDM_ASSERT(data_in_size <= SPDM_MAX_OPAQUE_DATA_SIZE);
280 :
281 77 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
282 19 : if ((spdm_context->connection_info.algorithm.other_params_support &
283 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1) {
284 : /* Check byte alignment */
285 15 : if ((data_in_size & 3) != 0) {
286 0 : return false;
287 : }
288 :
289 15 : spdm_general_opaque_data_table_header = data_in;
290 15 : if (data_in_size < sizeof(spdm_general_opaque_data_table_header_t)) {
291 0 : return false;
292 : }
293 15 : if (spdm_general_opaque_data_table_header->total_elements < 1) {
294 0 : return false;
295 : }
296 15 : opaque_element_table_header = (const void *)(spdm_general_opaque_data_table_header + 1);
297 :
298 15 : element_num = spdm_general_opaque_data_table_header->total_elements;
299 :
300 15 : data_element_size = data_in_size - sizeof(spdm_general_opaque_data_table_header_t);
301 :
302 33 : for (element_index = 0; element_index < element_num; element_index++) {
303 : /*ensure the opaque_element_table_header is valid*/
304 19 : if (total_element_len + sizeof(opaque_element_table_header_t) +
305 : sizeof(opaque_element_data_len) >
306 : data_element_size) {
307 0 : return false;
308 : }
309 :
310 : /*check element header id*/
311 19 : if (opaque_element_table_header->id > SPDM_REGISTRY_ID_MAX) {
312 0 : return false;
313 : }
314 :
315 19 : opaque_element_data_len = *(uint16_t *)((size_t)(opaque_element_table_header + 1) +
316 19 : opaque_element_table_header->vendor_len);
317 :
318 19 : current_element_len = sizeof(opaque_element_table_header_t) +
319 19 : opaque_element_table_header->vendor_len +
320 19 : sizeof(opaque_element_data_len) +
321 : opaque_element_data_len;
322 :
323 19 : if ((current_element_len & 3) != 0) {
324 13 : if (!libspdm_consttime_is_mem_equal(zero_padding,
325 : (uint8_t *)(size_t)
326 : (opaque_element_table_header) +
327 : current_element_len,
328 13 : 4 - (current_element_len & 3))) {
329 1 : return false;
330 : }
331 : }
332 : /* Add Padding*/
333 18 : current_element_len = (current_element_len + 3) & ~3;
334 :
335 18 : total_element_len += current_element_len;
336 :
337 18 : if (total_element_len > data_element_size) {
338 0 : return false;
339 : }
340 :
341 : /*move to next element*/
342 18 : opaque_element_table_header =
343 : (const opaque_element_table_header_t *)
344 : ((const uint8_t *)opaque_element_table_header +
345 : current_element_len);
346 : }
347 : }
348 : }
349 :
350 76 : return true;
351 : }
|