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_secured_message_lib.h"
8 :
9 794 : static void generate_iv(uint64_t sequence_number, uint8_t *iv, const uint8_t *salt,
10 : size_t aead_iv_size, uint8_t endian)
11 : {
12 : uint8_t iv_temp[LIBSPDM_MAX_AEAD_IV_SIZE];
13 : size_t index;
14 :
15 : /* Form the AEAD IV from the salt and the sequence number. */
16 794 : libspdm_copy_mem(iv, LIBSPDM_MAX_AEAD_IV_SIZE, salt, aead_iv_size);
17 :
18 794 : switch (endian) {
19 794 : case LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_LITTLE:
20 : case LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_BOTH:
21 : /* If little-endian then the sequence number is zero-extended to the higher indices.
22 : * The sequence number begins at the lowest index (0). */
23 794 : libspdm_copy_mem(iv_temp, sizeof(iv_temp), &sequence_number, sizeof(sequence_number));
24 7146 : for (index = 0; index < sizeof(sequence_number); index++) {
25 6352 : iv[index] = iv[index] ^ iv_temp[index];
26 : }
27 794 : break;
28 0 : case LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BIG:
29 : case LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BOTH:
30 : /* If big-endian then the sequence number is zero-extended to the lower indices.
31 : * The sequence number ends at the highest index (aead_size - 1). */
32 0 : sequence_number = libspdm_le_to_be_64(sequence_number);
33 0 : libspdm_copy_mem(iv_temp + (aead_iv_size - sizeof(sequence_number)),
34 : aead_iv_size,
35 : &sequence_number,
36 : sizeof(sequence_number));
37 0 : for (index = aead_iv_size - sizeof(sequence_number); index < aead_iv_size; index++) {
38 0 : iv[index] = iv[index] ^ iv_temp[index];
39 : }
40 0 : break;
41 : }
42 794 : }
43 :
44 0 : static uint8_t swap_endian(uint8_t endian)
45 : {
46 0 : switch (endian) {
47 0 : case LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_BOTH:
48 0 : return LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BIG;
49 0 : case LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BOTH:
50 0 : return LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_LITTLE;
51 0 : default:
52 0 : LIBSPDM_ASSERT(0);
53 0 : return 0;
54 : }
55 : }
56 :
57 327 : static bool is_sequence_number_endian_determined(uint8_t endian)
58 : {
59 : return ((endian == LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BIG) ||
60 327 : (endian == LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_LITTLE)) ? true : false;
61 : }
62 :
63 : /**
64 : * Encode an application message to a secured message.
65 : *
66 : * @param spdm_secured_message_context A pointer to the SPDM secured message context.
67 : * @param session_id The session ID of the SPDM session.
68 : * @param is_request_message Indicates if it is a request message.
69 : * @param app_message_size size in bytes of the application message data buffer.
70 : * @param app_message A pointer to a source buffer to store the application message.
71 : * It shall point to the scratch buffer in spdm_context.
72 : * On input, the app_message pointer shall point to a big enough buffer.
73 : * Before app_message, there is room for spdm_secured_message_cipher_header_t.
74 : * After (app_message + app_message_size), there is room for random bytes.
75 : * @param secured_message_size size in bytes of the secured message data buffer.
76 : * @param secured_message A pointer to a destination buffer to store the secured message.
77 : * It shall point to the acquired sender buffer.
78 : * @param spdm_secured_message_callbacks A pointer to a secured message callback functions structure.
79 : *
80 : * @retval RETURN_SUCCESS The application message is encoded successfully.
81 : * @retval RETURN_INVALID_PARAMETER The message is NULL or the message_size is zero.
82 : **/
83 466 : libspdm_return_t libspdm_encode_secured_message(
84 : void *spdm_secured_message_context, uint32_t session_id,
85 : bool is_request_message, size_t app_message_size,
86 : void *app_message, size_t *secured_message_size,
87 : void *secured_message,
88 : const libspdm_secured_message_callbacks_t *spdm_secured_message_callbacks)
89 : {
90 : libspdm_secured_message_context_t *secured_message_context;
91 : size_t total_secured_message_size;
92 : size_t plain_text_size;
93 : size_t cipher_text_size;
94 : size_t aead_tag_size;
95 : size_t aead_key_size;
96 : size_t aead_iv_size;
97 : uint8_t *a_data;
98 : uint8_t *enc_msg;
99 : uint8_t *dec_msg;
100 : uint8_t *tag;
101 : spdm_secured_message_a_data_header1_t *record_header1;
102 : spdm_secured_message_a_data_header2_t *record_header2;
103 : size_t record_header_size;
104 : spdm_secured_message_cipher_header_t *enc_msg_header;
105 : bool result;
106 : const uint8_t *key;
107 : uint8_t *salt;
108 : uint8_t iv[LIBSPDM_MAX_AEAD_IV_SIZE];
109 : uint64_t sequence_number;
110 : uint64_t sequence_num_in_header;
111 : uint8_t sequence_num_in_header_size;
112 : libspdm_session_type_t session_type;
113 : uint32_t rand_count;
114 : uint32_t max_rand_count;
115 : libspdm_session_state_t session_state;
116 : spdm_version_number_t secured_spdm_version;
117 : uint8_t version;
118 :
119 466 : secured_message_context = spdm_secured_message_context;
120 466 : secured_spdm_version = spdm_secured_message_callbacks->get_secured_spdm_version(
121 466 : secured_message_context->secured_message_version);
122 466 : version = (uint8_t)(secured_spdm_version >> SPDM_VERSION_NUMBER_SHIFT_BIT);
123 466 : if (version > SECURED_SPDM_VERSION_12) {
124 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
125 : }
126 :
127 466 : session_type = secured_message_context->session_type;
128 466 : LIBSPDM_ASSERT((session_type == LIBSPDM_SESSION_TYPE_MAC_ONLY) ||
129 : (session_type == LIBSPDM_SESSION_TYPE_ENC_MAC));
130 466 : session_state = secured_message_context->session_state;
131 466 : LIBSPDM_ASSERT((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) ||
132 : (session_state == LIBSPDM_SESSION_STATE_ESTABLISHED));
133 :
134 466 : aead_tag_size = secured_message_context->aead_tag_size;
135 466 : aead_key_size = secured_message_context->aead_key_size;
136 466 : aead_iv_size = secured_message_context->aead_iv_size;
137 :
138 466 : switch (session_state) {
139 67 : case LIBSPDM_SESSION_STATE_HANDSHAKING:
140 67 : if (is_request_message) {
141 34 : key = (const uint8_t *)secured_message_context->handshake_secret.
142 : request_handshake_encryption_key;
143 34 : salt = (uint8_t *)secured_message_context->handshake_secret.
144 : request_handshake_salt;
145 34 : sequence_number = secured_message_context->handshake_secret
146 : .request_handshake_sequence_number;
147 : } else {
148 33 : key = (const uint8_t *)secured_message_context->handshake_secret.
149 : response_handshake_encryption_key;
150 33 : salt = (uint8_t *)secured_message_context->handshake_secret.
151 : response_handshake_salt;
152 33 : sequence_number = secured_message_context->handshake_secret
153 : .response_handshake_sequence_number;
154 : }
155 67 : break;
156 399 : case LIBSPDM_SESSION_STATE_ESTABLISHED:
157 399 : if (is_request_message) {
158 201 : key = (const uint8_t *)secured_message_context->application_secret.
159 : request_data_encryption_key;
160 201 : salt = (uint8_t *)secured_message_context->application_secret.
161 : request_data_salt;
162 201 : sequence_number = secured_message_context->application_secret
163 : .request_data_sequence_number;
164 : } else {
165 198 : key = (const uint8_t *)secured_message_context->application_secret.
166 : response_data_encryption_key;
167 198 : salt = (uint8_t *)secured_message_context->application_secret.
168 : response_data_salt;
169 198 : sequence_number = secured_message_context->application_secret
170 : .response_data_sequence_number;
171 : }
172 399 : break;
173 0 : default:
174 0 : LIBSPDM_ASSERT(false);
175 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
176 : break;
177 : }
178 :
179 466 : if (sequence_number >= secured_message_context->max_spdm_session_sequence_number) {
180 0 : return LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW;
181 : }
182 :
183 466 : generate_iv(sequence_number, iv, salt, aead_iv_size,
184 466 : secured_message_context->sequence_number_endian);
185 :
186 466 : sequence_num_in_header = 0;
187 466 : sequence_num_in_header_size = spdm_secured_message_callbacks->get_sequence_number(
188 : sequence_number, (uint8_t *)&sequence_num_in_header);
189 466 : LIBSPDM_ASSERT(sequence_num_in_header_size <= sizeof(sequence_num_in_header));
190 :
191 466 : if (session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) {
192 67 : if (is_request_message) {
193 34 : secured_message_context->handshake_secret.request_handshake_sequence_number++;
194 : } else {
195 33 : secured_message_context->handshake_secret.response_handshake_sequence_number++;
196 : }
197 : } else {
198 399 : if (is_request_message) {
199 201 : secured_message_context->application_secret.request_data_sequence_number++;
200 : } else {
201 198 : secured_message_context->application_secret.response_data_sequence_number++;
202 : }
203 : }
204 :
205 466 : record_header_size = sizeof(spdm_secured_message_a_data_header1_t) +
206 466 : sequence_num_in_header_size +
207 : sizeof(spdm_secured_message_a_data_header2_t);
208 :
209 466 : switch (session_type) {
210 466 : case LIBSPDM_SESSION_TYPE_ENC_MAC:
211 466 : max_rand_count = spdm_secured_message_callbacks->get_max_random_number_count();
212 466 : if (max_rand_count != 0) {
213 466 : rand_count = 0;
214 466 : result = libspdm_get_random_number(sizeof(rand_count), (uint8_t *)&rand_count);
215 466 : if (!result) {
216 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
217 : }
218 466 : rand_count = (uint8_t)((rand_count % max_rand_count) + 1);
219 : } else {
220 0 : rand_count = 0;
221 : }
222 :
223 466 : plain_text_size = sizeof(spdm_secured_message_cipher_header_t) + app_message_size +
224 : rand_count;
225 466 : cipher_text_size = plain_text_size;
226 466 : total_secured_message_size = record_header_size + cipher_text_size + aead_tag_size;
227 :
228 466 : LIBSPDM_ASSERT(*secured_message_size >= total_secured_message_size);
229 466 : if (*secured_message_size < total_secured_message_size) {
230 0 : *secured_message_size = total_secured_message_size;
231 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
232 : }
233 466 : *secured_message_size = total_secured_message_size;
234 466 : record_header1 = (void *)secured_message;
235 466 : record_header2 = (void *)((uint8_t *)record_header1 +
236 466 : sizeof(spdm_secured_message_a_data_header1_t) +
237 : sequence_num_in_header_size);
238 466 : record_header1->session_id = session_id;
239 466 : libspdm_copy_mem(record_header1 + 1,
240 466 : *secured_message_size
241 466 : - ((uint8_t*)(record_header1 + 1) - (uint8_t*)secured_message),
242 : &sequence_num_in_header,
243 : sequence_num_in_header_size);
244 466 : record_header2->length = (uint16_t)(cipher_text_size + aead_tag_size);
245 :
246 466 : enc_msg_header =
247 : (void *)((uint8_t *)app_message - sizeof(spdm_secured_message_cipher_header_t));
248 466 : enc_msg_header->application_data_length = (uint16_t)app_message_size;
249 466 : result = libspdm_get_random_number(rand_count,
250 : (uint8_t *)enc_msg_header +
251 466 : sizeof(spdm_secured_message_cipher_header_t) +
252 : app_message_size);
253 466 : if (!result) {
254 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
255 : }
256 :
257 466 : a_data = (uint8_t *)record_header1;
258 466 : enc_msg = (uint8_t *)(record_header2 + 1);
259 466 : dec_msg = (uint8_t *)enc_msg_header;
260 466 : tag = (uint8_t *)record_header1 + record_header_size +
261 : cipher_text_size;
262 :
263 466 : result = libspdm_aead_encryption(
264 466 : secured_message_context->secured_message_version,
265 466 : secured_message_context->aead_cipher_suite, key,
266 : aead_key_size, iv, aead_iv_size, (uint8_t *)a_data,
267 : record_header_size, dec_msg, cipher_text_size, tag,
268 : aead_tag_size, enc_msg, &cipher_text_size);
269 466 : break;
270 :
271 0 : case LIBSPDM_SESSION_TYPE_MAC_ONLY:
272 0 : total_secured_message_size =
273 0 : record_header_size + app_message_size + aead_tag_size;
274 :
275 0 : LIBSPDM_ASSERT(*secured_message_size >= total_secured_message_size);
276 0 : if (*secured_message_size < total_secured_message_size) {
277 0 : *secured_message_size = total_secured_message_size;
278 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
279 : }
280 0 : *secured_message_size = total_secured_message_size;
281 0 : record_header1 = (void *)secured_message;
282 0 : record_header2 =
283 : (void *)((uint8_t *)record_header1 +
284 0 : sizeof(spdm_secured_message_a_data_header1_t) +
285 : sequence_num_in_header_size);
286 0 : record_header1->session_id = session_id;
287 0 : libspdm_copy_mem(record_header1 + 1,
288 0 : *secured_message_size
289 0 : - ((uint8_t*)(record_header1 + 1) - (uint8_t*)secured_message),
290 : &sequence_num_in_header,
291 : sequence_num_in_header_size);
292 0 : record_header2->length =
293 0 : (uint16_t)(app_message_size + aead_tag_size);
294 0 : libspdm_copy_mem(record_header2 + 1,
295 0 : *secured_message_size
296 0 : - ((uint8_t*)(record_header2 + 1) - (uint8_t*)secured_message),
297 : app_message, app_message_size);
298 0 : a_data = (uint8_t *)record_header1;
299 0 : tag = (uint8_t *)record_header1 + record_header_size + app_message_size;
300 :
301 0 : result = libspdm_aead_encryption(
302 0 : secured_message_context->secured_message_version,
303 0 : secured_message_context->aead_cipher_suite, key,
304 : aead_key_size, iv, aead_iv_size, (uint8_t *)a_data,
305 : record_header_size + app_message_size, NULL, 0, tag,
306 : aead_tag_size, NULL, NULL);
307 0 : break;
308 :
309 0 : default:
310 0 : LIBSPDM_ASSERT(false);
311 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
312 : }
313 466 : if (!result) {
314 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
315 : }
316 466 : return LIBSPDM_STATUS_SUCCESS;
317 : }
318 :
319 : /**
320 : * Decode an application message from a secured message.
321 : *
322 : * @param spdm_secured_message_context A pointer to the SPDM secured message context.
323 : * @param session_id The session ID of the SPDM session.
324 : * @param is_request_message Indicates if it is a request message.
325 : * @param secured_message_size size in bytes of the secured message data buffer.
326 : * @param secured_message A pointer to a source buffer to store the secured message.
327 : * It shall point to the acquired receiver buffer.
328 : * @param app_message_size size in bytes of the application message data buffer.
329 : * @param app_message A pointer to a destination buffer to store the application message.
330 : * It shall point to the scratch buffer in spdm_context.
331 : * On input, the app_message pointer shall point to a big enough buffer to hold the decrypted message
332 : * On output, the app_message pointer shall be inside of [app_message, app_message + app_message_size]
333 : * @param spdm_secured_message_callbacks A pointer to a secured message callback functions structure.
334 : *
335 : * @retval RETURN_SUCCESS The application message is decoded successfully.
336 : * @retval RETURN_INVALID_PARAMETER The message is NULL or the message_size is zero.
337 : * @retval RETURN_UNSUPPORTED The secured_message is unsupported.
338 : **/
339 328 : libspdm_return_t libspdm_decode_secured_message(
340 : void *spdm_secured_message_context, uint32_t session_id,
341 : bool is_request_message, size_t secured_message_size,
342 : void *secured_message, size_t *app_message_size,
343 : void **app_message,
344 : const libspdm_secured_message_callbacks_t *spdm_secured_message_callbacks)
345 : {
346 : libspdm_secured_message_context_t *secured_message_context;
347 : size_t plain_text_size;
348 : size_t cipher_text_size;
349 : size_t aead_tag_size;
350 : size_t aead_key_size;
351 : size_t aead_iv_size;
352 : const uint8_t *a_data;
353 : const uint8_t *enc_msg;
354 : uint8_t *dec_msg;
355 : const uint8_t *tag;
356 : spdm_secured_message_a_data_header1_t *record_header1;
357 : spdm_secured_message_a_data_header2_t *record_header2;
358 : size_t record_header_size;
359 : spdm_secured_message_cipher_header_t *enc_msg_header;
360 : bool result;
361 : const uint8_t *key;
362 : uint8_t *salt;
363 : uint8_t iv[LIBSPDM_MAX_AEAD_IV_SIZE];
364 : uint64_t sequence_number;
365 : uint64_t sequence_num_in_header;
366 : uint8_t sequence_num_in_header_size;
367 : libspdm_session_type_t session_type;
368 : libspdm_session_state_t session_state;
369 : libspdm_error_struct_t spdm_error;
370 : spdm_version_number_t secured_spdm_version;
371 : uint8_t version;
372 :
373 328 : spdm_error.error_code = 0;
374 328 : spdm_error.session_id = 0;
375 328 : libspdm_secured_message_set_last_spdm_error_struct(spdm_secured_message_context, &spdm_error);
376 :
377 328 : spdm_error.error_code = SPDM_ERROR_CODE_DECRYPT_ERROR;
378 328 : spdm_error.session_id = session_id;
379 :
380 328 : secured_message_context = spdm_secured_message_context;
381 328 : secured_spdm_version = spdm_secured_message_callbacks->get_secured_spdm_version(
382 328 : secured_message_context->secured_message_version);
383 328 : version = (uint8_t)(secured_spdm_version >> SPDM_VERSION_NUMBER_SHIFT_BIT);
384 328 : if (version > SECURED_SPDM_VERSION_12) {
385 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
386 : }
387 :
388 328 : session_type = secured_message_context->session_type;
389 328 : LIBSPDM_ASSERT((session_type == LIBSPDM_SESSION_TYPE_MAC_ONLY) ||
390 : (session_type == LIBSPDM_SESSION_TYPE_ENC_MAC));
391 328 : session_state = secured_message_context->session_state;
392 328 : LIBSPDM_ASSERT((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) ||
393 : (session_state == LIBSPDM_SESSION_STATE_ESTABLISHED));
394 :
395 328 : aead_tag_size = secured_message_context->aead_tag_size;
396 328 : aead_key_size = secured_message_context->aead_key_size;
397 328 : aead_iv_size = secured_message_context->aead_iv_size;
398 :
399 328 : switch (session_state) {
400 34 : case LIBSPDM_SESSION_STATE_HANDSHAKING:
401 34 : if (is_request_message) {
402 1 : key = (const uint8_t *)secured_message_context->handshake_secret.
403 : request_handshake_encryption_key;
404 1 : salt = (uint8_t *)secured_message_context->handshake_secret.
405 : request_handshake_salt;
406 1 : sequence_number =
407 : secured_message_context->handshake_secret.request_handshake_sequence_number;
408 : } else {
409 33 : key = (const uint8_t *)secured_message_context->handshake_secret.
410 : response_handshake_encryption_key;
411 33 : salt = (uint8_t *)secured_message_context->handshake_secret.
412 : response_handshake_salt;
413 33 : sequence_number =
414 : secured_message_context->handshake_secret.response_handshake_sequence_number;
415 : }
416 34 : break;
417 294 : case LIBSPDM_SESSION_STATE_ESTABLISHED:
418 294 : if (is_request_message) {
419 66 : key = (const uint8_t *)secured_message_context->application_secret.
420 : request_data_encryption_key;
421 66 : salt = (uint8_t *)secured_message_context->application_secret.
422 : request_data_salt;
423 66 : sequence_number =
424 : secured_message_context->application_secret.request_data_sequence_number;
425 : } else {
426 228 : key = (const uint8_t *)secured_message_context->application_secret.
427 : response_data_encryption_key;
428 228 : salt = (uint8_t *)secured_message_context->application_secret.
429 : response_data_salt;
430 228 : sequence_number =
431 : secured_message_context->application_secret.response_data_sequence_number;
432 : }
433 294 : break;
434 0 : default:
435 0 : LIBSPDM_ASSERT(false);
436 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
437 : }
438 :
439 328 : if (sequence_number >= secured_message_context->max_spdm_session_sequence_number) {
440 0 : libspdm_secured_message_set_last_spdm_error_struct(
441 : spdm_secured_message_context, &spdm_error);
442 0 : return LIBSPDM_STATUS_SEQUENCE_NUMBER_OVERFLOW;
443 : }
444 :
445 328 : generate_iv(sequence_number, iv, salt, aead_iv_size,
446 328 : secured_message_context->sequence_number_endian);
447 :
448 328 : sequence_num_in_header = 0;
449 : sequence_num_in_header_size =
450 328 : spdm_secured_message_callbacks->get_sequence_number(
451 : sequence_number, (uint8_t *)&sequence_num_in_header);
452 328 : LIBSPDM_ASSERT(sequence_num_in_header_size <= sizeof(sequence_num_in_header));
453 :
454 328 : if (session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) {
455 34 : if (is_request_message) {
456 1 : secured_message_context->handshake_secret.request_handshake_sequence_number++;
457 : } else {
458 33 : secured_message_context->handshake_secret.response_handshake_sequence_number++;
459 : }
460 : } else {
461 294 : if (is_request_message) {
462 66 : secured_message_context->application_secret.request_data_sequence_number++;
463 : } else {
464 228 : secured_message_context->application_secret.response_data_sequence_number++;
465 : }
466 : }
467 :
468 328 : record_header_size = sizeof(spdm_secured_message_a_data_header1_t) +
469 328 : sequence_num_in_header_size +
470 : sizeof(spdm_secured_message_a_data_header2_t);
471 :
472 328 : switch (session_type) {
473 328 : case LIBSPDM_SESSION_TYPE_ENC_MAC:
474 328 : if (secured_message_size < record_header_size + aead_tag_size) {
475 0 : libspdm_secured_message_set_last_spdm_error_struct(
476 : spdm_secured_message_context, &spdm_error);
477 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
478 : }
479 328 : record_header1 = secured_message;
480 328 : record_header2 =
481 : (void *)((uint8_t *)record_header1 +
482 328 : sizeof(spdm_secured_message_a_data_header1_t) +
483 : sequence_num_in_header_size);
484 328 : if (record_header1->session_id != session_id) {
485 0 : libspdm_secured_message_set_last_spdm_error_struct(
486 : spdm_secured_message_context, &spdm_error);
487 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
488 : }
489 328 : if (!libspdm_consttime_is_mem_equal(record_header1 + 1, &sequence_num_in_header,
490 : sequence_num_in_header_size)) {
491 1 : libspdm_secured_message_set_last_spdm_error_struct(
492 : spdm_secured_message_context, &spdm_error);
493 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
494 : }
495 327 : if (record_header2->length > secured_message_size - record_header_size) {
496 0 : libspdm_secured_message_set_last_spdm_error_struct(
497 : spdm_secured_message_context, &spdm_error);
498 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
499 : }
500 327 : if (record_header2->length < aead_tag_size) {
501 0 : libspdm_secured_message_set_last_spdm_error_struct(
502 : spdm_secured_message_context, &spdm_error);
503 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
504 : }
505 327 : cipher_text_size = (record_header2->length - aead_tag_size);
506 327 : if (cipher_text_size > *app_message_size) {
507 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
508 : }
509 327 : libspdm_zero_mem(*app_message, *app_message_size);
510 327 : enc_msg_header = (void *)(record_header2 + 1);
511 327 : a_data = (const uint8_t *)record_header1;
512 327 : enc_msg = (const uint8_t *)enc_msg_header;
513 327 : dec_msg = (uint8_t *)*app_message;
514 327 : enc_msg_header = (void *)dec_msg;
515 327 : tag = (const uint8_t *)record_header1 + record_header_size + cipher_text_size;
516 :
517 327 : result = libspdm_aead_decryption(
518 327 : secured_message_context->secured_message_version,
519 327 : secured_message_context->aead_cipher_suite, key,
520 : aead_key_size, iv, aead_iv_size, a_data,
521 : record_header_size, enc_msg, cipher_text_size, tag,
522 : aead_tag_size, dec_msg, &cipher_text_size);
523 :
524 : /* When the sequence number is 0 then it has the same encoding in both
525 : * big and little endian. The endianness can only be determined on the subsequent
526 : * decryption. */
527 327 : if (!is_sequence_number_endian_determined(
528 327 : secured_message_context->sequence_number_endian) && (sequence_number == 1)) {
529 :
530 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Sequence number endianness is not determined.\n"));
531 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Attempting to determine endianness.\n"));
532 :
533 0 : if (result) {
534 : /* Endianness is correct so set the endianness. */
535 0 : if (secured_message_context->sequence_number_endian ==
536 : LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_BOTH) {
537 0 : secured_message_context->sequence_number_endian =
538 : LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_LITTLE;
539 : } else {
540 0 : secured_message_context->sequence_number_endian =
541 : LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BIG;
542 : }
543 : } else {
544 : /* Endianness may be incorrect so try with the opposite endianness. */
545 0 : generate_iv(sequence_number, iv, salt, aead_iv_size,
546 0 : swap_endian(secured_message_context->sequence_number_endian));
547 :
548 0 : result = libspdm_aead_decryption(
549 0 : secured_message_context->secured_message_version,
550 0 : secured_message_context->aead_cipher_suite, key,
551 : aead_key_size, iv, aead_iv_size, a_data,
552 : record_header_size, enc_msg, cipher_text_size, tag,
553 : aead_tag_size, dec_msg, &cipher_text_size);
554 :
555 0 : if (result) {
556 : /* Endianness is correct so set the endianness. */
557 0 : secured_message_context->sequence_number_endian =
558 0 : swap_endian(secured_message_context->sequence_number_endian);
559 : }
560 : }
561 : }
562 :
563 327 : if (!result) {
564 : /* Backup keys are valid, fail and alert rollback and retry is possible. */
565 27 : if ((is_request_message && secured_message_context->requester_backup_valid) ||
566 27 : ((!is_request_message) && secured_message_context->responder_backup_valid)) {
567 27 : return LIBSPDM_STATUS_SESSION_TRY_DISCARD_KEY_UPDATE;
568 : }
569 :
570 0 : libspdm_secured_message_set_last_spdm_error_struct(
571 : spdm_secured_message_context, &spdm_error);
572 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
573 : }
574 300 : plain_text_size = enc_msg_header->application_data_length;
575 300 : if (plain_text_size > cipher_text_size) {
576 0 : libspdm_secured_message_set_last_spdm_error_struct(
577 : spdm_secured_message_context, &spdm_error);
578 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
579 : }
580 :
581 300 : LIBSPDM_ASSERT(*app_message_size >= plain_text_size);
582 300 : *app_message = enc_msg_header + 1;
583 300 : *app_message_size = plain_text_size;
584 300 : break;
585 :
586 0 : case LIBSPDM_SESSION_TYPE_MAC_ONLY:
587 0 : if (secured_message_size < record_header_size + aead_tag_size) {
588 0 : libspdm_secured_message_set_last_spdm_error_struct(
589 : spdm_secured_message_context, &spdm_error);
590 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
591 : }
592 0 : record_header1 = secured_message;
593 0 : record_header2 =
594 : (void *)((uint8_t *)record_header1 +
595 0 : sizeof(spdm_secured_message_a_data_header1_t) +
596 : sequence_num_in_header_size);
597 0 : if (record_header1->session_id != session_id) {
598 0 : libspdm_secured_message_set_last_spdm_error_struct(
599 : spdm_secured_message_context, &spdm_error);
600 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
601 : }
602 0 : if (!libspdm_consttime_is_mem_equal(record_header1 + 1, &sequence_num_in_header,
603 : sequence_num_in_header_size)) {
604 0 : libspdm_secured_message_set_last_spdm_error_struct(
605 : spdm_secured_message_context, &spdm_error);
606 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
607 : }
608 0 : if (record_header2->length >
609 0 : secured_message_size - record_header_size) {
610 0 : libspdm_secured_message_set_last_spdm_error_struct(
611 : spdm_secured_message_context, &spdm_error);
612 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
613 : }
614 0 : if (record_header2->length < aead_tag_size) {
615 0 : libspdm_secured_message_set_last_spdm_error_struct(
616 : spdm_secured_message_context, &spdm_error);
617 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
618 : }
619 0 : a_data = (uint8_t *)record_header1;
620 0 : tag = (uint8_t *)record_header1 + record_header_size +
621 0 : record_header2->length - aead_tag_size;
622 :
623 0 : result = libspdm_aead_decryption(
624 0 : secured_message_context->secured_message_version,
625 0 : secured_message_context->aead_cipher_suite, key,
626 : aead_key_size, iv, aead_iv_size, a_data,
627 0 : record_header_size + record_header2->length - aead_tag_size,
628 : NULL, 0, tag, aead_tag_size, NULL, NULL);
629 :
630 : /* When the sequence number is 0 then it has the same encoding in both
631 : * big and little endian. The endianness can only be determined on the subsequent
632 : * decryption. */
633 0 : if (!is_sequence_number_endian_determined(
634 0 : secured_message_context->sequence_number_endian) && (sequence_number == 1)) {
635 0 : if (result) {
636 : /* Endianness is correct so set the endianness. */
637 0 : if (secured_message_context->sequence_number_endian ==
638 : LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_BOTH) {
639 0 : secured_message_context->sequence_number_endian =
640 : LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_LITTLE;
641 : } else {
642 0 : secured_message_context->sequence_number_endian =
643 : LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BIG;
644 : }
645 : } else {
646 : /* Endianness may be incorrect so try with the opposite endianness. */
647 0 : generate_iv(sequence_number, iv, salt, aead_iv_size,
648 0 : swap_endian(secured_message_context->sequence_number_endian));
649 :
650 0 : result = libspdm_aead_decryption(
651 0 : secured_message_context->secured_message_version,
652 0 : secured_message_context->aead_cipher_suite, key,
653 : aead_key_size, iv, aead_iv_size, a_data,
654 0 : record_header_size + record_header2->length - aead_tag_size,
655 : NULL, 0, tag, aead_tag_size, NULL, NULL);
656 :
657 0 : if (result) {
658 : /* Endianness is correct so set the endianness. */
659 0 : secured_message_context->sequence_number_endian =
660 0 : swap_endian(secured_message_context->sequence_number_endian);
661 : }
662 : }
663 : }
664 :
665 0 : if (!result) {
666 : /* Backup keys are valid, fail and alert rollback and retry is possible. */
667 0 : if ((is_request_message && secured_message_context->requester_backup_valid) ||
668 0 : ((!is_request_message) && secured_message_context->responder_backup_valid)) {
669 0 : return LIBSPDM_STATUS_SESSION_TRY_DISCARD_KEY_UPDATE;
670 : }
671 :
672 0 : libspdm_secured_message_set_last_spdm_error_struct(
673 : spdm_secured_message_context, &spdm_error);
674 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
675 : }
676 :
677 0 : plain_text_size = record_header2->length - aead_tag_size;
678 0 : LIBSPDM_ASSERT(*app_message_size >= plain_text_size);
679 0 : *app_message = record_header2 + 1;
680 0 : *app_message_size = plain_text_size;
681 0 : break;
682 :
683 0 : default:
684 0 : LIBSPDM_ASSERT(false);
685 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
686 : }
687 :
688 300 : return LIBSPDM_STATUS_SUCCESS;
689 : }
|