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