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_requester_lib.h"
8 : : #include "internal/libspdm_secured_message_lib.h"
9 : :
10 : : #if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)
11 : :
12 : : #pragma pack(1)
13 : : typedef struct {
14 : : spdm_message_header_t header;
15 : : uint8_t dummy_data[sizeof(spdm_error_data_response_not_ready_t)];
16 : : } libspdm_key_update_response_mine_t;
17 : : #pragma pack()
18 : :
19 : : /**
20 : : * This function sends KEY_UPDATE
21 : : * to update keys for an SPDM Session.
22 : : *
23 : : * After keys are updated, this function also uses VERIFY_NEW_KEY to verify the key.
24 : : *
25 : : * @param spdm_context A pointer to the SPDM context.
26 : : * @param session_id The session ID of the session.
27 : : * @param single_direction true means the operation is UPDATE_KEY.
28 : : * false means the operation is UPDATE_ALL_KEYS.
29 : : * @param key_updated true means the operation is to verify key(s).
30 : : * false means the operation is to update and verify key(s).
31 : : **/
32 : 94 : static libspdm_return_t libspdm_try_key_update(libspdm_context_t *spdm_context,
33 : : uint32_t session_id,
34 : : bool single_direction, bool *key_updated)
35 : : {
36 : : libspdm_return_t status;
37 : : bool result;
38 : : spdm_key_update_request_t *spdm_request;
39 : : size_t spdm_request_size;
40 : : libspdm_key_update_response_mine_t *spdm_response;
41 : : size_t spdm_response_size;
42 : : libspdm_session_info_t *session_info;
43 : : libspdm_session_state_t session_state;
44 : : uint8_t *message;
45 : : size_t message_size;
46 : : size_t transport_header_size;
47 : :
48 [ - + ]: 94 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
49 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
50 : : }
51 : :
52 [ + + ]: 94 : if (!libspdm_is_capabilities_flag_supported(
53 : : spdm_context, true,
54 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP,
55 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP)) {
56 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
57 : : }
58 : :
59 [ + + ]: 93 : if (spdm_context->connection_info.connection_state <
60 : : LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
61 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
62 : : }
63 : : session_info =
64 : 92 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
65 [ - + ]: 92 : if (session_info == NULL) {
66 : 0 : LIBSPDM_ASSERT(false);
67 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
68 : : }
69 : 92 : session_state = libspdm_secured_message_get_session_state(
70 : : session_info->secured_message_context);
71 [ + + ]: 92 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
72 : 1 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
73 : : }
74 : :
75 : 91 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info, SPDM_KEY_UPDATE);
76 : :
77 [ + + ]: 91 : if (!(*key_updated)) {
78 : :
79 : : /* Update key*/
80 : :
81 : 87 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
82 : 87 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
83 [ - + ]: 87 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
84 : 0 : return status;
85 : : }
86 [ - + ]: 87 : LIBSPDM_ASSERT (message_size >= transport_header_size +
87 : : spdm_context->local_context.capability.transport_tail_size);
88 : 87 : spdm_request = (void *)(message + transport_header_size);
89 : 87 : spdm_request_size = message_size - transport_header_size -
90 : 87 : spdm_context->local_context.capability.transport_tail_size;
91 : :
92 [ - + ]: 87 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_update_request_t));
93 : 87 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
94 : 87 : spdm_request->header.request_response_code = SPDM_KEY_UPDATE;
95 [ + + ]: 87 : if (single_direction) {
96 : 58 : spdm_request->header.param1 = SPDM_KEY_UPDATE_OPERATIONS_UPDATE_KEY;
97 : : } else {
98 : 29 : spdm_request->header.param1 = SPDM_KEY_UPDATE_OPERATIONS_UPDATE_ALL_KEYS;
99 : : }
100 : 87 : spdm_request->header.param2 = 0;
101 : :
102 [ - + ]: 87 : if (!libspdm_get_random_number(sizeof(spdm_request->header.param2),
103 : : &spdm_request->header.param2)) {
104 : 0 : libspdm_release_sender_buffer (spdm_context);
105 : 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
106 : : }
107 : :
108 : 87 : spdm_request_size = sizeof(spdm_key_update_request_t);
109 : :
110 : : /* If updating both, create new responder key*/
111 [ + + ]: 87 : if (!single_direction) {
112 : 29 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
113 : : "libspdm_create_update_session_data_key[%x] Responder\n",
114 : : session_id));
115 : 29 : result = libspdm_create_update_session_data_key(
116 : : session_info->secured_message_context,
117 : : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
118 [ - + ]: 29 : if (!result) {
119 : 0 : libspdm_release_sender_buffer (spdm_context);
120 : 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
121 : : }
122 : : }
123 : :
124 : 87 : status = libspdm_send_spdm_request(spdm_context, &session_id,
125 : : spdm_request_size, spdm_request);
126 [ + + ]: 87 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
127 : 1 : libspdm_release_sender_buffer (spdm_context);
128 : 1 : return status;
129 : : }
130 : :
131 : 86 : libspdm_release_sender_buffer (spdm_context);
132 : 86 : spdm_request = (void *)spdm_context->last_spdm_request;
133 : :
134 : : /* receive */
135 : :
136 : 86 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
137 [ - + ]: 86 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
138 : 0 : return status;
139 : : }
140 [ - + ]: 86 : LIBSPDM_ASSERT (message_size >= transport_header_size);
141 : 86 : spdm_response = (void *)(message);
142 : 86 : spdm_response_size = message_size;
143 : :
144 : 86 : status = libspdm_receive_spdm_response(
145 : : spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
146 : :
147 [ + - ]: 86 : if (!LIBSPDM_STATUS_IS_ERROR(status)) {
148 [ + + ]: 86 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
149 : 50 : status = libspdm_handle_error_response_main(
150 : : spdm_context, &session_id,
151 : : &spdm_response_size, (void **)&spdm_response,
152 : : SPDM_KEY_UPDATE, SPDM_KEY_UPDATE_ACK);
153 [ - + ]: 36 : } else if (spdm_response_size != sizeof(spdm_key_update_response_t)) {
154 : : /* this message can only be in secured session thus
155 : : * don't need to consider transport layer padding, just check its exact size */
156 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
157 [ - + ]: 36 : } else if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
158 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
159 [ + + ]: 36 : } else if ((spdm_response->header.request_response_code !=
160 : 35 : SPDM_KEY_UPDATE_ACK) ||
161 [ + + ]: 35 : (spdm_response->header.param1 != spdm_request->header.param1) ||
162 [ + + ]: 33 : (spdm_response->header.param2 != spdm_request->header.param2)) {
163 : 4 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
164 : : }
165 : : }
166 : :
167 [ + + ]: 86 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
168 [ + + ]: 52 : if (!single_direction) {
169 : 26 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
170 : : "libspdm_activate_update_session_data_key[%x] Responder old\n",
171 : : session_id));
172 : 26 : result = libspdm_activate_update_session_data_key(
173 : : session_info->secured_message_context,
174 : : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, false);
175 [ - + ]: 26 : if (!result) {
176 : 0 : libspdm_release_receiver_buffer (spdm_context);
177 : 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
178 : : }
179 : : }
180 : 52 : libspdm_release_receiver_buffer (spdm_context);
181 : 52 : return status;
182 : : }
183 : :
184 [ + + ]: 34 : if (!single_direction) {
185 : 3 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
186 : : "libspdm_activate_update_session_data_key[%x] Responder new\n",
187 : : session_id));
188 : 3 : result = libspdm_activate_update_session_data_key(
189 : : session_info->secured_message_context,
190 : : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, true);
191 [ - + ]: 3 : if (!result) {
192 : 0 : libspdm_release_receiver_buffer (spdm_context);
193 : 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
194 : : }
195 : : }
196 : :
197 : 34 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
198 : : "libspdm_create_update_session_data_key[%x] Requester\n",
199 : : session_id));
200 : 34 : result = libspdm_create_update_session_data_key(
201 : : session_info->secured_message_context,
202 : : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
203 [ - + ]: 34 : if (!result) {
204 : 0 : libspdm_release_receiver_buffer (spdm_context);
205 : 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
206 : : }
207 : 34 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
208 : : "libspdm_activate_update_session_data_key[%x] Requester new\n",
209 : : session_id));
210 : 34 : result = libspdm_activate_update_session_data_key(
211 : : session_info->secured_message_context,
212 : : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER, true);
213 [ - + ]: 34 : if (!result) {
214 : 0 : libspdm_release_receiver_buffer (spdm_context);
215 : 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
216 : : }
217 : :
218 : : /* -=[Log Message Phase]=- */
219 : : #if LIBSPDM_ENABLE_MSG_LOG
220 : 34 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
221 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
222 : :
223 : 34 : libspdm_release_receiver_buffer (spdm_context);
224 : : }
225 : :
226 : 38 : *key_updated = true;
227 : :
228 : :
229 : : /* Verify key*/
230 : :
231 : 38 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
232 : 38 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
233 [ - + ]: 38 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
234 : 0 : return status;
235 : : }
236 [ - + ]: 38 : LIBSPDM_ASSERT (message_size >= transport_header_size +
237 : : spdm_context->local_context.capability.transport_tail_size);
238 : 38 : spdm_request = (void *)(message + transport_header_size);
239 : 38 : spdm_request_size = message_size - transport_header_size -
240 : 38 : spdm_context->local_context.capability.transport_tail_size;
241 : :
242 [ - + ]: 38 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_key_update_request_t));
243 : 38 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
244 : 38 : spdm_request->header.request_response_code = SPDM_KEY_UPDATE;
245 : 38 : spdm_request->header.param1 = SPDM_KEY_UPDATE_OPERATIONS_VERIFY_NEW_KEY;
246 : 38 : spdm_request->header.param2 = 1;
247 [ - + ]: 38 : if (!libspdm_get_random_number(sizeof(spdm_request->header.param2),
248 : : &spdm_request->header.param2)) {
249 : 0 : libspdm_release_sender_buffer (spdm_context);
250 : 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
251 : : }
252 : 38 : spdm_request_size = sizeof(spdm_key_update_request_t);
253 : :
254 : 38 : status = libspdm_send_spdm_request(spdm_context, &session_id,
255 : : spdm_request_size, spdm_request);
256 [ - + ]: 38 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
257 : 0 : libspdm_release_sender_buffer (spdm_context);
258 : 0 : return status;
259 : : }
260 : 38 : libspdm_release_sender_buffer (spdm_context);
261 : 38 : spdm_request = (void *)spdm_context->last_spdm_request;
262 : :
263 : : /* receive */
264 : :
265 : 38 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
266 [ - + ]: 38 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
267 : 0 : return status;
268 : : }
269 [ - + ]: 38 : LIBSPDM_ASSERT (message_size >= transport_header_size);
270 : 38 : spdm_response = (void *)(message);
271 : 38 : spdm_response_size = message_size;
272 : :
273 : 38 : status = libspdm_receive_spdm_response(
274 : : spdm_context, &session_id, &spdm_response_size, (void **)&spdm_response);
275 [ - + ]: 38 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
276 : 0 : libspdm_release_receiver_buffer (spdm_context);
277 : 0 : return status;
278 : : }
279 : :
280 [ + + ]: 38 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
281 : 26 : status = libspdm_handle_error_response_main(
282 : : spdm_context, &session_id,
283 : : &spdm_response_size, (void **)&spdm_response,
284 : : SPDM_KEY_UPDATE, SPDM_KEY_UPDATE_ACK);
285 [ + + ]: 26 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
286 : 25 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Failed\n", session_id));
287 : 25 : libspdm_release_receiver_buffer (spdm_context);
288 : 25 : return status;
289 : : }
290 : : }
291 : :
292 : : /* this message can only be in secured session
293 : : * thus don't need to consider transport layer padding, just check its exact size */
294 [ - + ]: 13 : if (spdm_response_size != sizeof(spdm_key_update_response_t)) {
295 : 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Failed\n", session_id));
296 : 0 : libspdm_release_receiver_buffer (spdm_context);
297 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
298 : : }
299 : :
300 [ - + ]: 13 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
301 : 0 : libspdm_release_receiver_buffer (spdm_context);
302 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
303 : : }
304 : :
305 [ + + ]: 13 : if ((spdm_response->header.request_response_code !=
306 : 12 : SPDM_KEY_UPDATE_ACK) ||
307 [ + + ]: 12 : (spdm_response->header.param1 != spdm_request->header.param1) ||
308 [ + + ]: 11 : (spdm_response->header.param2 != spdm_request->header.param2)) {
309 : 3 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Failed\n", session_id));
310 : 3 : libspdm_release_receiver_buffer (spdm_context);
311 : 3 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
312 : : }
313 : 10 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "SpdmVerifyKey[%x] Success\n", session_id));
314 : :
315 : : /* -=[Log Message Phase]=- */
316 : : #if LIBSPDM_ENABLE_MSG_LOG
317 : 10 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
318 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
319 : :
320 : 10 : libspdm_release_receiver_buffer (spdm_context);
321 : 10 : return LIBSPDM_STATUS_SUCCESS;
322 : : }
323 : :
324 : 85 : libspdm_return_t libspdm_key_update(void *spdm_context, uint32_t session_id,
325 : : bool single_direction)
326 : : {
327 : : libspdm_context_t *context;
328 : : size_t retry;
329 : : uint64_t retry_delay_time;
330 : : libspdm_return_t status;
331 : : bool key_updated;
332 : :
333 : 85 : context = spdm_context;
334 : 85 : key_updated = false;
335 : 85 : context->crypto_request = true;
336 : 85 : retry = context->retry_times;
337 : 85 : retry_delay_time = context->retry_delay_time;
338 : : do {
339 : 94 : status = libspdm_try_key_update(spdm_context, session_id,
340 : : single_direction, &key_updated);
341 [ + + ]: 94 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
342 : 82 : return status;
343 : : }
344 : :
345 : 12 : libspdm_sleep(retry_delay_time);
346 [ + + ]: 12 : } while (retry-- != 0);
347 : :
348 : 3 : return status;
349 : : }
350 : :
351 : : #endif /* (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP) */
|