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_responder_lib.h"
8 : : #include "internal/libspdm_secured_message_lib.h"
9 : :
10 : : #if LIBSPDM_ENABLE_CAPABILITY_PSK_CAP
11 : :
12 : 11 : bool libspdm_verify_psk_finish_req_hmac(libspdm_context_t *spdm_context,
13 : : libspdm_session_info_t *session_info,
14 : : const uint8_t *hmac, size_t hmac_size)
15 : : {
16 : : uint8_t hmac_data[LIBSPDM_MAX_HASH_SIZE];
17 : : size_t hash_size;
18 : : bool result;
19 : : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
20 : : uint8_t *th_curr_data;
21 : : size_t th_curr_data_size;
22 : : libspdm_th_managed_buffer_t th_curr;
23 : : uint8_t hash_data[LIBSPDM_MAX_HASH_SIZE];
24 : : #endif
25 : :
26 : 11 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
27 [ - + ]: 11 : LIBSPDM_ASSERT(hmac_size == hash_size);
28 : :
29 : : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
30 : : result = libspdm_calculate_th_for_finish(spdm_context, session_info, NULL,
31 : : 0, NULL, 0, &th_curr);
32 : : if (!result) {
33 : : return false;
34 : : }
35 : : th_curr_data = libspdm_get_managed_buffer(&th_curr);
36 : : th_curr_data_size = libspdm_get_managed_buffer_size(&th_curr);
37 : :
38 : : result = libspdm_hash_all (spdm_context->connection_info.algorithm.base_hash_algo,
39 : : th_curr_data, th_curr_data_size, hash_data);
40 : : if (!result) {
41 : : return false;
42 : : }
43 : :
44 : : result = libspdm_hmac_all_with_request_finished_key(
45 : : session_info->secured_message_context, hash_data,
46 : : hash_size, hmac_data);
47 : : if (!result) {
48 : : return false;
49 : : }
50 : : #else
51 : 11 : result = libspdm_calculate_th_hmac_for_finish_req(
52 : : spdm_context, session_info, &hash_size, hmac_data);
53 [ - + ]: 11 : if (!result) {
54 : 0 : return false;
55 : : }
56 : : #endif
57 : 11 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc th_curr hmac - "));
58 : 11 : LIBSPDM_INTERNAL_DUMP_DATA(hmac_data, hash_size);
59 : 11 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
60 : :
61 [ + + ]: 11 : if (!libspdm_consttime_is_mem_equal(hmac, hmac_data, hash_size)) {
62 : 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "!!! verify_psk_finish_req_hmac - FAIL !!!\n"));
63 : 2 : return false;
64 : : }
65 : 9 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_psk_finish_req_hmac - PASS !!!\n"));
66 : 9 : return true;
67 : : }
68 : :
69 : 22 : libspdm_return_t libspdm_get_response_psk_finish(libspdm_context_t *spdm_context,
70 : : size_t request_size,
71 : : const void *request,
72 : : size_t *response_size,
73 : : void *response)
74 : : {
75 : : uint32_t session_id;
76 : : bool result;
77 : : uint32_t hmac_size;
78 : : spdm_psk_finish_response_t *spdm_response;
79 : : libspdm_session_info_t *session_info;
80 : : uint8_t th2_hash_data[LIBSPDM_MAX_HASH_SIZE];
81 : : const spdm_psk_finish_request_t *spdm_request;
82 : : libspdm_return_t status;
83 : : libspdm_session_state_t session_state;
84 : : uint8_t *ptr;
85 : : size_t opaque_data_entry_size;
86 : : const uint8_t *req_opaque_data;
87 : : size_t req_opaque_data_size;
88 : : uint8_t *opaque_data;
89 : : size_t opaque_data_size;
90 : :
91 : 22 : spdm_request = request;
92 : :
93 : : /* -=[Check Parameters Phase]=- */
94 [ - + ]: 22 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_PSK_FINISH);
95 : :
96 [ - + ]: 22 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
97 : 0 : return libspdm_generate_error_response(spdm_context,
98 : : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
99 : : SPDM_PSK_FINISH,
100 : : response_size, response);
101 : : }
102 : :
103 [ - + ]: 22 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
104 : 0 : return libspdm_generate_error_response(spdm_context,
105 : : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
106 : : response_size, response);
107 : : }
108 [ + + ]: 22 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
109 : 3 : return libspdm_responder_handle_response_state(
110 : : spdm_context,
111 : 3 : spdm_request->header.request_response_code,
112 : : response_size, response);
113 : : }
114 [ + + ]: 19 : if (!libspdm_is_capabilities_flag_supported(
115 : : spdm_context, false,
116 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP,
117 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT)) {
118 : 1 : return libspdm_generate_error_response(
119 : : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
120 : : SPDM_PSK_FINISH, response_size, response);
121 : : }
122 [ + + ]: 18 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
123 : 1 : return libspdm_generate_error_response(spdm_context,
124 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
125 : : 0, response_size, response);
126 : : }
127 : :
128 [ - + ]: 17 : if (!spdm_context->last_spdm_request_session_id_valid) {
129 [ # # ]: 0 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
130 : 0 : return libspdm_generate_error_response(spdm_context,
131 : : SPDM_ERROR_CODE_SESSION_REQUIRED, 0,
132 : : response_size, response);
133 : : } else {
134 : 0 : return libspdm_generate_error_response(spdm_context,
135 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
136 : : response_size, response);
137 : : }
138 : : }
139 : 17 : session_id = spdm_context->last_spdm_request_session_id;
140 : : session_info =
141 : 17 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
142 [ - + ]: 17 : if (session_info == NULL) {
143 [ # # ]: 0 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
144 : 0 : return libspdm_generate_error_response(spdm_context,
145 : : SPDM_ERROR_CODE_SESSION_REQUIRED, 0,
146 : : response_size, response);
147 : : } else {
148 : 0 : return libspdm_generate_error_response(spdm_context,
149 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
150 : : response_size, response);
151 : : }
152 : : }
153 [ - + ]: 17 : if (!session_info->use_psk) {
154 : 0 : return libspdm_generate_error_response(spdm_context,
155 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
156 : : response_size, response);
157 : : }
158 : 17 : session_state = libspdm_secured_message_get_session_state(
159 : : session_info->secured_message_context);
160 [ + + ]: 17 : if (session_state != LIBSPDM_SESSION_STATE_HANDSHAKING) {
161 : 1 : return libspdm_generate_error_response(spdm_context,
162 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
163 : : response_size, response);
164 : : }
165 : :
166 : : /* remove HMAC*/
167 : 16 : hmac_size = libspdm_get_hash_size(
168 : : spdm_context->connection_info.algorithm.base_hash_algo);
169 : :
170 : 16 : ptr = (uint8_t *)(size_t)spdm_request + sizeof(spdm_psk_finish_request_t);
171 [ + + ]: 16 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
172 [ - + ]: 4 : if (request_size < sizeof(spdm_psk_finish_request_t) + sizeof(uint16_t)) {
173 : 0 : return libspdm_generate_error_response(spdm_context,
174 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
175 : : response_size, response);
176 : : }
177 : 4 : req_opaque_data_size = libspdm_read_uint16((const uint8_t *)request +
178 : : sizeof(spdm_psk_finish_request_t));
179 : 4 : ptr += sizeof(uint16_t);
180 [ - + ]: 4 : if (req_opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) {
181 : 0 : return libspdm_generate_error_response(spdm_context,
182 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
183 : : response_size, response);
184 : : }
185 : 4 : if (request_size < sizeof(spdm_psk_finish_request_t) +
186 [ + + ]: 4 : sizeof(uint16_t) + req_opaque_data_size) {
187 : 1 : return libspdm_generate_error_response(spdm_context,
188 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
189 : : response_size, response);
190 : : }
191 : 3 : req_opaque_data = ptr;
192 : 3 : ptr += req_opaque_data_size;
193 : 3 : opaque_data_entry_size = sizeof(uint16_t) + req_opaque_data_size;
194 : : } else {
195 : 12 : opaque_data_entry_size = 0;
196 : : }
197 : :
198 : : /* this message can only be in secured session
199 : : * thus don't need to consider transport layer padding, just check its exact size */
200 [ + + ]: 15 : if (request_size != sizeof(spdm_psk_finish_request_t) + opaque_data_entry_size + hmac_size) {
201 : 4 : return libspdm_generate_error_response(spdm_context,
202 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
203 : : response_size, response);
204 : : }
205 : :
206 : 11 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
207 : 11 : spdm_request->header.request_response_code);
208 : :
209 : 11 : status = libspdm_append_message_f(spdm_context, session_info, false, request,
210 : : request_size - hmac_size);
211 [ - + ]: 11 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
212 : 0 : return libspdm_generate_error_response(spdm_context,
213 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
214 : : response_size, response);
215 : : }
216 : :
217 : 11 : result = libspdm_verify_psk_finish_req_hmac(
218 : : spdm_context, session_info,
219 : : ptr, hmac_size);
220 [ + + ]: 11 : if (!result) {
221 [ + - ]: 2 : if ((spdm_context->handle_error_return_policy &
222 : : LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) {
223 : 2 : return libspdm_generate_error_response(
224 : : spdm_context, SPDM_ERROR_CODE_DECRYPT_ERROR, 0,
225 : : response_size, response);
226 : : } else {
227 : : /**
228 : : * just ignore this message
229 : : * return UNSUPPORTED and clear response_size to continue the dispatch without send response
230 : : **/
231 : 0 : *response_size = 0;
232 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
233 : : }
234 : : }
235 : 9 : status = libspdm_append_message_f(
236 : : spdm_context, session_info, false,
237 : : ptr, hmac_size);
238 [ - + ]: 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
239 : 0 : return libspdm_generate_error_response(spdm_context,
240 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
241 : : response_size, response);
242 : : }
243 : :
244 [ + + ]: 9 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
245 : 3 : opaque_data_entry_size = sizeof(uint16_t);
246 : : } else {
247 : 6 : opaque_data_entry_size = 0;
248 : : }
249 : :
250 : : /* response_size should be large enough to hold a psk finish response without opaque data. */
251 [ - + ]: 9 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size);
252 : 9 : libspdm_zero_mem(response, *response_size);
253 : 9 : spdm_response = response;
254 : :
255 : 9 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
256 : 9 : spdm_response->header.request_response_code = SPDM_PSK_FINISH_RSP;
257 : 9 : spdm_response->header.param1 = 0;
258 : 9 : spdm_response->header.param2 = 0;
259 : :
260 : 9 : ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_finish_response_t);
261 [ + + ]: 9 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
262 : 3 : opaque_data_size = *response_size - sizeof(spdm_psk_finish_response_t) -
263 : : opaque_data_entry_size;
264 : 3 : opaque_data = ptr + opaque_data_entry_size;
265 : :
266 [ + + ]: 3 : if ((spdm_context->connection_info.algorithm.other_params_support &
267 : : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE) {
268 : 1 : opaque_data_size = 0;
269 : : } else {
270 : 4 : status = libspdm_psk_finish_rsp_opaque_data(
271 : 2 : spdm_context, session_id, spdm_request->header.spdm_version,
272 : : req_opaque_data, req_opaque_data_size,
273 : : opaque_data, &opaque_data_size);
274 [ - + ]: 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
275 : 0 : return libspdm_generate_error_response(spdm_context,
276 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
277 : : response_size, response);
278 : : }
279 : :
280 [ + + ]: 2 : if (opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) {
281 : 1 : return libspdm_generate_error_response(spdm_context,
282 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
283 : : response_size, response);
284 : : }
285 : : }
286 : 2 : libspdm_write_uint16(ptr, (uint16_t)opaque_data_size);
287 : 2 : opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size;
288 : 2 : ptr += opaque_data_entry_size;
289 : : }
290 : :
291 : 8 : *response_size = sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size;
292 : :
293 : 8 : status = libspdm_append_message_f(spdm_context, session_info, false, spdm_response,
294 : : *response_size);
295 [ - + ]: 8 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
296 : 0 : return libspdm_generate_error_response(spdm_context,
297 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
298 : : response_size, response);
299 : : }
300 : :
301 : 8 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n", session_id));
302 : 8 : result = libspdm_calculate_th2_hash(spdm_context, session_info, false,
303 : : th2_hash_data);
304 [ - + ]: 8 : if (!result) {
305 : 0 : return libspdm_generate_error_response(spdm_context,
306 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
307 : : response_size, response);
308 : : }
309 : 8 : result = libspdm_generate_session_data_key(
310 : : session_info->secured_message_context, th2_hash_data);
311 [ - + ]: 8 : if (!result) {
312 : 0 : return libspdm_generate_error_response(spdm_context,
313 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
314 : : response_size, response);
315 : : }
316 : :
317 : : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
318 [ + + + - ]: 9 : if ((spdm_context->local_context.heartbeat_period != 0) &&
319 : 1 : libspdm_is_capabilities_flag_supported(
320 : : spdm_context, false,
321 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
322 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
323 : 1 : result = libspdm_start_watchdog(
324 : 1 : spdm_context, session_id, spdm_context->local_context.heartbeat_period * 2);
325 [ - + ]: 1 : if (!result) {
326 : 0 : return libspdm_generate_error_response(spdm_context,
327 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
328 : : response_size, response);
329 : : }
330 : : }
331 : : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
332 : :
333 : 8 : return LIBSPDM_STATUS_SUCCESS;
334 : : }
335 : :
336 : : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP */
|