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 9 : 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 9 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
27 9 : 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 9 : result = libspdm_calculate_th_hmac_for_finish_req(
52 : spdm_context, session_info, &hash_size, hmac_data);
53 9 : if (!result) {
54 0 : return false;
55 : }
56 : #endif
57 9 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Calc th_curr hmac - "));
58 9 : LIBSPDM_INTERNAL_DUMP_DATA(hmac_data, hash_size);
59 9 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
60 :
61 9 : 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 7 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "!!! verify_psk_finish_req_hmac - PASS !!!\n"));
66 7 : return true;
67 : }
68 :
69 19 : 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 19 : spdm_request = request;
92 :
93 : /* -=[Check Parameters Phase]=- */
94 19 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_PSK_FINISH);
95 :
96 19 : 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 19 : 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 19 : 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 16 : 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 15 : 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 14 : 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 14 : session_id = spdm_context->last_spdm_request_session_id;
140 : session_info =
141 14 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
142 14 : 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 14 : 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 14 : session_state = libspdm_secured_message_get_session_state(
159 : session_info->secured_message_context);
160 14 : 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 13 : hmac_size = libspdm_get_hash_size(
168 : spdm_context->connection_info.algorithm.base_hash_algo);
169 :
170 13 : ptr = (uint8_t *)(size_t)spdm_request + sizeof(spdm_psk_finish_request_t);
171 13 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
172 4 : req_opaque_data_size = libspdm_read_uint16((const uint8_t *)request +
173 : sizeof(spdm_psk_finish_request_t));
174 4 : ptr += sizeof(uint16_t);
175 4 : if (req_opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) {
176 0 : return libspdm_generate_error_response(spdm_context,
177 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
178 : response_size, response);
179 : }
180 4 : if (request_size < sizeof(spdm_psk_finish_request_t) +
181 4 : sizeof(uint16_t) + req_opaque_data_size) {
182 1 : return libspdm_generate_error_response(spdm_context,
183 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
184 : response_size, response);
185 : }
186 3 : req_opaque_data = ptr;
187 3 : ptr += req_opaque_data_size;
188 3 : opaque_data_entry_size = sizeof(uint16_t) + req_opaque_data_size;
189 : } else {
190 9 : opaque_data_entry_size = 0;
191 : }
192 :
193 : /* this message can only be in secured session
194 : * thus don't need to consider transport layer padding, just check its exact size */
195 12 : if (request_size != sizeof(spdm_psk_finish_request_t) + opaque_data_entry_size + hmac_size) {
196 3 : return libspdm_generate_error_response(spdm_context,
197 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
198 : response_size, response);
199 : }
200 :
201 9 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
202 9 : spdm_request->header.request_response_code);
203 :
204 9 : status = libspdm_append_message_f(spdm_context, session_info, false, request,
205 : request_size - hmac_size);
206 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
207 0 : return libspdm_generate_error_response(spdm_context,
208 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
209 : response_size, response);
210 : }
211 :
212 9 : result = libspdm_verify_psk_finish_req_hmac(
213 : spdm_context, session_info,
214 : ptr, hmac_size);
215 9 : if (!result) {
216 2 : if ((spdm_context->handle_error_return_policy &
217 : LIBSPDM_DATA_HANDLE_ERROR_RETURN_POLICY_DROP_ON_DECRYPT_ERROR) == 0) {
218 2 : return libspdm_generate_error_response(
219 : spdm_context, SPDM_ERROR_CODE_DECRYPT_ERROR, 0,
220 : response_size, response);
221 : } else {
222 : /**
223 : * just ignore this message
224 : * return UNSUPPORTED and clear response_size to continue the dispatch without send response
225 : **/
226 0 : *response_size = 0;
227 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
228 : }
229 : }
230 7 : status = libspdm_append_message_f(
231 : spdm_context, session_info, false,
232 : ptr, hmac_size);
233 7 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
234 0 : return libspdm_generate_error_response(spdm_context,
235 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
236 : response_size, response);
237 : }
238 :
239 7 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
240 3 : opaque_data_entry_size = sizeof(uint16_t);
241 : } else {
242 4 : opaque_data_entry_size = 0;
243 : }
244 :
245 : /* response_size should be large enough to hold a psk finish response without opaque data. */
246 7 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size);
247 7 : libspdm_zero_mem(response, *response_size);
248 7 : spdm_response = response;
249 :
250 7 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
251 7 : spdm_response->header.request_response_code = SPDM_PSK_FINISH_RSP;
252 7 : spdm_response->header.param1 = 0;
253 7 : spdm_response->header.param2 = 0;
254 :
255 7 : ptr = (uint8_t *)spdm_response + sizeof(spdm_psk_finish_response_t);
256 7 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_14) {
257 3 : opaque_data_size = *response_size - sizeof(spdm_psk_finish_response_t) -
258 : opaque_data_entry_size;
259 3 : opaque_data = ptr + opaque_data_entry_size;
260 :
261 3 : if ((spdm_context->connection_info.algorithm.other_params_support &
262 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE) {
263 1 : opaque_data_size = 0;
264 : } else {
265 4 : status = libspdm_psk_finish_rsp_opaque_data(
266 2 : spdm_context, session_id, spdm_request->header.spdm_version,
267 : req_opaque_data, req_opaque_data_size,
268 : opaque_data, &opaque_data_size);
269 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
270 0 : return libspdm_generate_error_response(spdm_context,
271 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
272 : response_size, response);
273 : }
274 :
275 2 : if (opaque_data_size > SPDM_MAX_OPAQUE_DATA_SIZE) {
276 1 : return libspdm_generate_error_response(spdm_context,
277 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
278 : response_size, response);
279 : }
280 : }
281 2 : libspdm_write_uint16(ptr, (uint16_t)opaque_data_size);
282 2 : opaque_data_entry_size = sizeof(uint16_t) + opaque_data_size;
283 2 : ptr += opaque_data_entry_size;
284 : }
285 :
286 6 : *response_size = sizeof(spdm_psk_finish_response_t) + opaque_data_entry_size;
287 :
288 6 : status = libspdm_append_message_f(spdm_context, session_info, false, spdm_response,
289 : *response_size);
290 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
291 0 : return libspdm_generate_error_response(spdm_context,
292 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
293 : response_size, response);
294 : }
295 :
296 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "libspdm_generate_session_data_key[%x]\n", session_id));
297 6 : result = libspdm_calculate_th2_hash(spdm_context, session_info, false,
298 : th2_hash_data);
299 6 : if (!result) {
300 0 : return libspdm_generate_error_response(spdm_context,
301 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
302 : response_size, response);
303 : }
304 6 : result = libspdm_generate_session_data_key(
305 : session_info->secured_message_context, th2_hash_data);
306 6 : if (!result) {
307 0 : return libspdm_generate_error_response(spdm_context,
308 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
309 : response_size, response);
310 : }
311 :
312 : #if LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP
313 6 : if (libspdm_is_capabilities_flag_supported(
314 : spdm_context, false,
315 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP,
316 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP)) {
317 0 : result = libspdm_start_watchdog(
318 0 : session_id, spdm_context->local_context.heartbeat_period * 2);
319 0 : if (!result) {
320 0 : return libspdm_generate_error_response(spdm_context,
321 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
322 : response_size, response);
323 : }
324 : }
325 : #endif /* LIBSPDM_ENABLE_CAPABILITY_HBEAT_CAP */
326 :
327 6 : return LIBSPDM_STATUS_SUCCESS;
328 : }
329 :
330 : #endif /* LIBSPDM_ENABLE_CAPABILITY_PSK_CAP */
|