Branch data 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 : 1003 : 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 : 1003 : libspdm_copy_mem(iv, LIBSPDM_MAX_AEAD_IV_SIZE, salt, aead_iv_size);
17 : :
18 [ + + - ]: 1003 : switch (endian) {
19 : 992 : 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 : 992 : libspdm_copy_mem(iv_temp, sizeof(iv_temp), &sequence_number, sizeof(sequence_number));
24 [ + + ]: 8928 : for (index = 0; index < sizeof(sequence_number); index++) {
25 : 7936 : iv[index] = iv[index] ^ iv_temp[index];
26 : : }
27 : 992 : 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_iv_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 : 1003 : }
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 : 419 : static bool is_sequence_number_endian_determined(uint8_t endian)
58 : : {
59 : : return ((endian == LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_BIG_DEC_BIG) ||
60 [ + + + + ]: 419 : (endian == LIBSPDM_DATA_SESSION_SEQ_NUM_ENC_LITTLE_DEC_LITTLE)) ? true : false;
61 : : }
62 : :
63 : 580 : 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 : 580 : secured_message_context = spdm_secured_message_context;
100 : 580 : secured_spdm_version = spdm_secured_message_callbacks->get_secured_spdm_version(
101 : 580 : secured_message_context->secured_message_version);
102 : 580 : version = (uint8_t)(secured_spdm_version >> SPDM_VERSION_NUMBER_SHIFT_BIT);
103 : : /* Only check the major version. The minor version is not checked. */
104 [ + + ]: 580 : if ((version >> 4) != (SECURED_SPDM_VERSION_10 >> 4)) {
105 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
106 : : }
107 : :
108 : 579 : session_type = secured_message_context->session_type;
109 [ + + - + ]: 579 : LIBSPDM_ASSERT((session_type == LIBSPDM_SESSION_TYPE_MAC_ONLY) ||
110 : : (session_type == LIBSPDM_SESSION_TYPE_ENC_MAC));
111 : 579 : session_state = secured_message_context->session_state;
112 [ + + - + ]: 579 : LIBSPDM_ASSERT((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) ||
113 : : (session_state == LIBSPDM_SESSION_STATE_ESTABLISHED));
114 : :
115 : 579 : aead_tag_size = secured_message_context->aead_tag_size;
116 : 579 : aead_key_size = secured_message_context->aead_key_size;
117 : 579 : aead_iv_size = secured_message_context->aead_iv_size;
118 : :
119 [ + + - ]: 579 : switch (session_state) {
120 : 94 : case LIBSPDM_SESSION_STATE_HANDSHAKING:
121 [ + + ]: 94 : if (is_request_message) {
122 : 44 : key = (const uint8_t *)secured_message_context->handshake_secret.
123 : : request_handshake_encryption_key;
124 : 44 : salt = (uint8_t *)secured_message_context->handshake_secret.
125 : : request_handshake_salt;
126 : 44 : sequence_number = secured_message_context->handshake_secret
127 : : .request_handshake_sequence_number;
128 : : } else {
129 : 50 : key = (const uint8_t *)secured_message_context->handshake_secret.
130 : : response_handshake_encryption_key;
131 : 50 : salt = (uint8_t *)secured_message_context->handshake_secret.
132 : : response_handshake_salt;
133 : 50 : sequence_number = secured_message_context->handshake_secret
134 : : .response_handshake_sequence_number;
135 : : }
136 : 94 : break;
137 : 485 : case LIBSPDM_SESSION_STATE_ESTABLISHED:
138 [ + + ]: 485 : if (is_request_message) {
139 : 254 : key = (const uint8_t *)secured_message_context->application_secret.
140 : : request_data_encryption_key;
141 : 254 : salt = (uint8_t *)secured_message_context->application_secret.
142 : : request_data_salt;
143 : 254 : sequence_number = secured_message_context->application_secret
144 : : .request_data_sequence_number;
145 : : } else {
146 : 231 : key = (const uint8_t *)secured_message_context->application_secret.
147 : : response_data_encryption_key;
148 : 231 : salt = (uint8_t *)secured_message_context->application_secret.
149 : : response_data_salt;
150 : 231 : sequence_number = secured_message_context->application_secret
151 : : .response_data_sequence_number;
152 : : }
153 : 485 : 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 [ + - - + ]: 579 : 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 : 579 : generate_iv(sequence_number, iv, salt, aead_iv_size,
170 : 579 : secured_message_context->sequence_number_endian);
171 : :
172 : 579 : sequence_num_in_header = 0;
173 : 579 : sequence_num_in_header_size = spdm_secured_message_callbacks->get_sequence_number(
174 : : sequence_number, (uint8_t *)&sequence_num_in_header);
175 [ - + ]: 579 : LIBSPDM_ASSERT(sequence_num_in_header_size <= sizeof(sequence_num_in_header));
176 : :
177 [ + + ]: 579 : if (session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) {
178 [ + + ]: 94 : if (is_request_message) {
179 : 44 : secured_message_context->handshake_secret.request_handshake_sequence_number++;
180 : : } else {
181 : 50 : secured_message_context->handshake_secret.response_handshake_sequence_number++;
182 : : }
183 : : } else {
184 [ + + ]: 485 : if (is_request_message) {
185 : 254 : secured_message_context->application_secret.request_data_sequence_number++;
186 : : } else {
187 : 231 : secured_message_context->application_secret.response_data_sequence_number++;
188 : : }
189 : : }
190 : :
191 : 579 : record_header_size = sizeof(spdm_secured_message_a_data_header1_t) +
192 : 579 : sequence_num_in_header_size +
193 : : sizeof(spdm_secured_message_a_data_header2_t);
194 : :
195 [ + + - ]: 579 : switch (session_type) {
196 : 576 : case LIBSPDM_SESSION_TYPE_ENC_MAC:
197 : 576 : max_rand_count = spdm_secured_message_callbacks->get_max_random_number_count();
198 [ + + ]: 576 : if (max_rand_count != 0) {
199 : 568 : rand_count = 0;
200 : 568 : result = libspdm_get_random_number(sizeof(rand_count), (uint8_t *)&rand_count);
201 [ - + ]: 568 : if (!result) {
202 : 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
203 : : }
204 : 568 : rand_count = (uint8_t)((rand_count % max_rand_count) + 1);
205 : : } else {
206 : 8 : rand_count = 0;
207 : : }
208 : :
209 : 576 : plain_text_size = sizeof(spdm_secured_message_cipher_header_t) + app_message_size +
210 : : rand_count;
211 : 576 : cipher_text_size = plain_text_size;
212 : 576 : total_secured_message_size = record_header_size + cipher_text_size + aead_tag_size;
213 : :
214 [ - + ]: 576 : LIBSPDM_ASSERT(*secured_message_size >= total_secured_message_size);
215 [ - + ]: 576 : 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 : 576 : *secured_message_size = total_secured_message_size;
220 : 576 : record_header1 = (void *)secured_message;
221 : 576 : record_header2 = (void *)((uint8_t *)record_header1 +
222 : 576 : sizeof(spdm_secured_message_a_data_header1_t) +
223 : : sequence_num_in_header_size);
224 : 576 : record_header1->session_id = session_id;
225 : 576 : libspdm_copy_mem(record_header1 + 1,
226 : 576 : *secured_message_size
227 : 576 : - ((uint8_t*)(record_header1 + 1) - (uint8_t*)secured_message),
228 : : &sequence_num_in_header,
229 : : sequence_num_in_header_size);
230 : 576 : record_header2->length = (uint16_t)(cipher_text_size + aead_tag_size);
231 : :
232 : 576 : enc_msg_header =
233 : : (void *)((uint8_t *)app_message - sizeof(spdm_secured_message_cipher_header_t));
234 : 576 : enc_msg_header->application_data_length = (uint16_t)app_message_size;
235 : 576 : result = libspdm_get_random_number(rand_count,
236 : : (uint8_t *)enc_msg_header +
237 : 576 : sizeof(spdm_secured_message_cipher_header_t) +
238 : : app_message_size);
239 [ - + ]: 576 : if (!result) {
240 : 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
241 : : }
242 : :
243 : 576 : a_data = (uint8_t *)record_header1;
244 : 576 : enc_msg = (uint8_t *)(record_header2 + 1);
245 : 576 : dec_msg = (uint8_t *)enc_msg_header;
246 : 576 : tag = (uint8_t *)record_header1 + record_header_size +
247 : : cipher_text_size;
248 : :
249 : 576 : result = libspdm_aead_encryption(
250 : 576 : secured_message_context->secured_message_version,
251 : 576 : 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 : 576 : break;
256 : :
257 : 3 : case LIBSPDM_SESSION_TYPE_MAC_ONLY:
258 : 3 : total_secured_message_size =
259 : 3 : record_header_size + app_message_size + aead_tag_size;
260 : :
261 [ - + ]: 3 : LIBSPDM_ASSERT(*secured_message_size >= total_secured_message_size);
262 [ - + ]: 3 : 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 : 3 : *secured_message_size = total_secured_message_size;
267 : 3 : record_header1 = (void *)secured_message;
268 : 3 : record_header2 =
269 : : (void *)((uint8_t *)record_header1 +
270 : 3 : sizeof(spdm_secured_message_a_data_header1_t) +
271 : : sequence_num_in_header_size);
272 : 3 : record_header1->session_id = session_id;
273 : 3 : libspdm_copy_mem(record_header1 + 1,
274 : 3 : *secured_message_size
275 : 3 : - ((uint8_t*)(record_header1 + 1) - (uint8_t*)secured_message),
276 : : &sequence_num_in_header,
277 : : sequence_num_in_header_size);
278 : 3 : record_header2->length =
279 : 3 : (uint16_t)(app_message_size + aead_tag_size);
280 : 3 : libspdm_copy_mem(record_header2 + 1,
281 : 3 : *secured_message_size
282 : 3 : - ((uint8_t*)(record_header2 + 1) - (uint8_t*)secured_message),
283 : : app_message, app_message_size);
284 : 3 : a_data = (uint8_t *)record_header1;
285 : 3 : tag = (uint8_t *)record_header1 + record_header_size + app_message_size;
286 : :
287 : 3 : result = libspdm_aead_encryption(
288 : 3 : secured_message_context->secured_message_version,
289 : 3 : 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 : 3 : break;
294 : :
295 : 0 : default:
296 : 0 : LIBSPDM_ASSERT(false);
297 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
298 : : }
299 [ - + ]: 579 : if (!result) {
300 : 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
301 : : }
302 : 579 : return LIBSPDM_STATUS_SUCCESS;
303 : : }
304 : :
305 : 421 : 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 : 421 : spdm_error.error_code = 0;
340 : 421 : spdm_error.session_id = 0;
341 : 421 : libspdm_secured_message_set_last_spdm_error_struct(spdm_secured_message_context, &spdm_error);
342 : :
343 : 421 : spdm_error.error_code = SPDM_ERROR_CODE_DECRYPT_ERROR;
344 : 421 : spdm_error.session_id = session_id;
345 : :
346 : 421 : secured_message_context = spdm_secured_message_context;
347 : 421 : secured_spdm_version = spdm_secured_message_callbacks->get_secured_spdm_version(
348 : 421 : secured_message_context->secured_message_version);
349 : 421 : version = (uint8_t)(secured_spdm_version >> SPDM_VERSION_NUMBER_SHIFT_BIT);
350 : : /* Only check the major version. The minor version is not checked. */
351 [ + + ]: 421 : if ((version >> 4) != (SECURED_SPDM_VERSION_10 >> 4)) {
352 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
353 : : }
354 : :
355 : 420 : session_type = secured_message_context->session_type;
356 [ + + - + ]: 420 : LIBSPDM_ASSERT((session_type == LIBSPDM_SESSION_TYPE_MAC_ONLY) ||
357 : : (session_type == LIBSPDM_SESSION_TYPE_ENC_MAC));
358 : 420 : session_state = secured_message_context->session_state;
359 [ + + - + ]: 420 : LIBSPDM_ASSERT((session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) ||
360 : : (session_state == LIBSPDM_SESSION_STATE_ESTABLISHED));
361 : :
362 : 420 : aead_tag_size = secured_message_context->aead_tag_size;
363 : 420 : aead_key_size = secured_message_context->aead_key_size;
364 : 420 : aead_iv_size = secured_message_context->aead_iv_size;
365 : :
366 [ + + - ]: 420 : switch (session_state) {
367 : 56 : case LIBSPDM_SESSION_STATE_HANDSHAKING:
368 [ + + ]: 56 : if (is_request_message) {
369 : 6 : key = (const uint8_t *)secured_message_context->handshake_secret.
370 : : request_handshake_encryption_key;
371 : 6 : salt = (uint8_t *)secured_message_context->handshake_secret.
372 : : request_handshake_salt;
373 : 6 : sequence_number =
374 : : secured_message_context->handshake_secret.request_handshake_sequence_number;
375 : : } else {
376 : 50 : key = (const uint8_t *)secured_message_context->handshake_secret.
377 : : response_handshake_encryption_key;
378 : 50 : salt = (uint8_t *)secured_message_context->handshake_secret.
379 : : response_handshake_salt;
380 : 50 : sequence_number =
381 : : secured_message_context->handshake_secret.response_handshake_sequence_number;
382 : : }
383 : 56 : break;
384 : 364 : case LIBSPDM_SESSION_STATE_ESTABLISHED:
385 [ + + ]: 364 : if (is_request_message) {
386 : 105 : key = (const uint8_t *)secured_message_context->application_secret.
387 : : request_data_encryption_key;
388 : 105 : salt = (uint8_t *)secured_message_context->application_secret.
389 : : request_data_salt;
390 : 105 : sequence_number =
391 : : secured_message_context->application_secret.request_data_sequence_number;
392 : : } else {
393 : 259 : key = (const uint8_t *)secured_message_context->application_secret.
394 : : response_data_encryption_key;
395 : 259 : salt = (uint8_t *)secured_message_context->application_secret.
396 : : response_data_salt;
397 : 259 : sequence_number =
398 : : secured_message_context->application_secret.response_data_sequence_number;
399 : : }
400 : 364 : 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 [ + - - + ]: 420 : 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 : 420 : generate_iv(sequence_number, iv, salt, aead_iv_size,
418 : 420 : secured_message_context->sequence_number_endian);
419 : :
420 : 420 : sequence_num_in_header = 0;
421 : : sequence_num_in_header_size =
422 : 420 : spdm_secured_message_callbacks->get_sequence_number(
423 : : sequence_number, (uint8_t *)&sequence_num_in_header);
424 [ - + ]: 420 : LIBSPDM_ASSERT(sequence_num_in_header_size <= sizeof(sequence_num_in_header));
425 : :
426 [ + + ]: 420 : if (session_state == LIBSPDM_SESSION_STATE_HANDSHAKING) {
427 [ + + ]: 56 : if (is_request_message) {
428 : 6 : secured_message_context->handshake_secret.request_handshake_sequence_number++;
429 : : } else {
430 : 50 : secured_message_context->handshake_secret.response_handshake_sequence_number++;
431 : : }
432 : : } else {
433 [ + + ]: 364 : if (is_request_message) {
434 : 105 : secured_message_context->application_secret.request_data_sequence_number++;
435 : : } else {
436 : 259 : secured_message_context->application_secret.response_data_sequence_number++;
437 : : }
438 : : }
439 : :
440 : 420 : record_header_size = sizeof(spdm_secured_message_a_data_header1_t) +
441 : 420 : sequence_num_in_header_size +
442 : : sizeof(spdm_secured_message_a_data_header2_t);
443 : :
444 [ + + - ]: 420 : switch (session_type) {
445 : 417 : case LIBSPDM_SESSION_TYPE_ENC_MAC:
446 [ - + ]: 417 : 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 : 417 : record_header1 = secured_message;
452 : 417 : record_header2 =
453 : : (void *)((uint8_t *)record_header1 +
454 : 417 : sizeof(spdm_secured_message_a_data_header1_t) +
455 : : sequence_num_in_header_size);
456 [ - + ]: 417 : 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 [ + + ]: 417 : 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 [ - + ]: 416 : 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 [ - + ]: 416 : 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 : 416 : cipher_text_size = (record_header2->length - aead_tag_size);
478 [ - + ]: 416 : if (cipher_text_size > *app_message_size) {
479 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
480 : : }
481 : 416 : libspdm_zero_mem(*app_message, *app_message_size);
482 : 416 : enc_msg_header = (void *)(record_header2 + 1);
483 : 416 : a_data = (const uint8_t *)record_header1;
484 : 416 : enc_msg = (const uint8_t *)enc_msg_header;
485 : 416 : dec_msg = (uint8_t *)*app_message;
486 : 416 : enc_msg_header = (void *)dec_msg;
487 : 416 : tag = (const uint8_t *)record_header1 + record_header_size + cipher_text_size;
488 : :
489 : 416 : result = libspdm_aead_decryption(
490 : 416 : secured_message_context->secured_message_version,
491 : 416 : 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 [ + + ]: 416 : if (!is_sequence_number_endian_determined(
500 [ + + ]: 421 : 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 [ + + ]: 416 : 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 : 389 : plain_text_size = enc_msg_header->application_data_length;
547 [ + + ]: 389 : 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 [ - + ]: 388 : LIBSPDM_ASSERT(*app_message_size >= plain_text_size);
554 : 388 : *app_message = enc_msg_header + 1;
555 : 388 : *app_message_size = plain_text_size;
556 : 388 : break;
557 : :
558 : 3 : case LIBSPDM_SESSION_TYPE_MAC_ONLY:
559 [ - + ]: 3 : 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 : 3 : record_header1 = secured_message;
565 : 3 : record_header2 =
566 : : (void *)((uint8_t *)record_header1 +
567 : 3 : sizeof(spdm_secured_message_a_data_header1_t) +
568 : : sequence_num_in_header_size);
569 [ - + ]: 3 : 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 [ - + ]: 3 : 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 : 3 : if (record_header2->length >
581 [ - + ]: 3 : 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 [ - + ]: 3 : 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 : 3 : a_data = (uint8_t *)record_header1;
592 : 3 : tag = (uint8_t *)record_header1 + record_header_size +
593 : 3 : record_header2->length - aead_tag_size;
594 : :
595 : 3 : result = libspdm_aead_decryption(
596 : 3 : secured_message_context->secured_message_version,
597 : 3 : secured_message_context->aead_cipher_suite, key,
598 : : aead_key_size, iv, aead_iv_size, a_data,
599 : 3 : 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 [ + + ]: 3 : if (!is_sequence_number_endian_determined(
606 [ + + ]: 5 : 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 [ + + ]: 3 : if (!result) {
638 : : /* Backup keys are valid, fail and alert rollback and retry is possible. */
639 [ - + - - ]: 1 : if ((is_request_message && secured_message_context->requester_backup_valid) ||
640 [ + - - + ]: 1 : ((!is_request_message) && secured_message_context->responder_backup_valid)) {
641 : 0 : return LIBSPDM_STATUS_SESSION_TRY_DISCARD_KEY_UPDATE;
642 : : }
643 : :
644 : 1 : libspdm_secured_message_set_last_spdm_error_struct(
645 : : spdm_secured_message_context, &spdm_error);
646 : 1 : 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 : 390 : return LIBSPDM_STATUS_SUCCESS;
661 : : }
|