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