Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2025 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_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)
11 :
12 : /**
13 : * Process the SPDM KEY_UPDATE request and return the response.
14 : *
15 : * @param spdm_context A pointer to the SPDM context.
16 : * @param request_size size in bytes of the request data.
17 : * @param request A pointer to the request data.
18 : * @param response_size size in bytes of the response data.
19 : * On input, it means the size in bytes of response data buffer.
20 : * On output, it means the size in bytes of copied response data buffer if RETURN_SUCCESS is returned,
21 : * and means the size in bytes of desired response data buffer if RETURN_BUFFER_TOO_SMALL is returned.
22 : * @param response A pointer to the response data.
23 : *
24 : * @retval RETURN_SUCCESS The request is processed and the response is returned.
25 : * @retval RETURN_BUFFER_TOO_SMALL The buffer is too small to hold the data.
26 : * @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device.
27 : * @retval RETURN_SECURITY_VIOLATION Any verification fails.
28 : **/
29 27 : libspdm_return_t libspdm_get_response_key_update(libspdm_context_t *spdm_context,
30 : size_t request_size,
31 : const void *request,
32 : size_t *response_size,
33 : void *response)
34 : {
35 : uint32_t session_id;
36 : spdm_key_update_response_t *spdm_response;
37 : const spdm_key_update_request_t *spdm_request;
38 : spdm_key_update_request_t *prev_spdm_request;
39 : libspdm_session_info_t *session_info;
40 : libspdm_session_state_t session_state;
41 : spdm_key_update_request_t spdm_key_init_update_operation;
42 : bool result;
43 :
44 27 : spdm_request = request;
45 :
46 : /* -=[Check Parameters Phase]=- */
47 27 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_KEY_UPDATE);
48 :
49 27 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
50 0 : return libspdm_generate_error_response(spdm_context,
51 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
52 : SPDM_KEY_UPDATE,
53 : response_size, response);
54 : }
55 :
56 27 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
57 0 : return libspdm_generate_error_response(spdm_context,
58 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
59 : response_size, response);
60 : }
61 27 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
62 3 : return libspdm_responder_handle_response_state(
63 : spdm_context,
64 3 : spdm_request->header.request_response_code,
65 : response_size, response);
66 : }
67 :
68 24 : if (!libspdm_is_capabilities_flag_supported(
69 : spdm_context, false,
70 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP,
71 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP)) {
72 1 : return libspdm_generate_error_response(
73 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
74 : SPDM_KEY_UPDATE, response_size, response);
75 : }
76 23 : if (spdm_context->connection_info.connection_state <
77 : LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
78 1 : return libspdm_generate_error_response(spdm_context,
79 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
80 : 0, response_size, response);
81 : }
82 :
83 22 : if (!spdm_context->last_spdm_request_session_id_valid) {
84 0 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
85 0 : return libspdm_generate_error_response(spdm_context,
86 : SPDM_ERROR_CODE_SESSION_REQUIRED, 0,
87 : response_size, response);
88 : } else {
89 0 : return libspdm_generate_error_response(spdm_context,
90 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
91 : response_size, response);
92 : }
93 : }
94 22 : session_id = spdm_context->last_spdm_request_session_id;
95 : session_info =
96 22 : libspdm_get_session_info_via_session_id(spdm_context, session_id);
97 22 : if (session_info == NULL) {
98 0 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) {
99 0 : return libspdm_generate_error_response(spdm_context,
100 : SPDM_ERROR_CODE_SESSION_REQUIRED, 0,
101 : response_size, response);
102 : } else {
103 0 : return libspdm_generate_error_response(spdm_context,
104 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
105 : response_size, response);
106 : }
107 : }
108 22 : session_state = libspdm_secured_message_get_session_state(
109 : session_info->secured_message_context);
110 22 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
111 1 : return libspdm_generate_error_response(spdm_context,
112 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
113 : response_size, response);
114 : }
115 :
116 : /* this message can only be in secured session
117 : * thus don't need to consider transport layer padding, just check its exact size */
118 21 : if (request_size != sizeof(spdm_key_update_request_t)) {
119 4 : return libspdm_generate_error_response(spdm_context,
120 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
121 : response_size, response);
122 : }
123 :
124 : /*last key operation*/
125 17 : prev_spdm_request = &(session_info->last_key_update_request);
126 :
127 : /*the end status of the successful key update overall flow*/
128 17 : libspdm_zero_mem(&spdm_key_init_update_operation, sizeof(spdm_key_update_request_t));
129 :
130 17 : switch (spdm_request->header.param1) {
131 6 : case SPDM_KEY_UPDATE_OPERATIONS_TABLE_UPDATE_KEY:
132 6 : if(!libspdm_consttime_is_mem_equal(prev_spdm_request,
133 : &spdm_key_init_update_operation,
134 : sizeof(spdm_key_update_request_t))) {
135 2 : return libspdm_generate_error_response(spdm_context,
136 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
137 : response_size, response);
138 : }
139 :
140 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
141 : "libspdm_create_update_session_data_key[%x] Requester\n",
142 : session_id));
143 4 : result = libspdm_create_update_session_data_key(
144 : session_info->secured_message_context,
145 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
146 4 : if (!result) {
147 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
148 : }
149 4 : libspdm_trigger_key_update_callback(
150 : spdm_context, session_id, LIBSPDM_KEY_UPDATE_OPERATION_CREATE_UPDATE,
151 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
152 :
153 : /*save the last update operation*/
154 4 : libspdm_copy_mem(prev_spdm_request, sizeof(spdm_key_update_request_t),
155 : spdm_request, request_size);
156 4 : break;
157 5 : case SPDM_KEY_UPDATE_OPERATIONS_TABLE_UPDATE_ALL_KEYS:
158 5 : if(!libspdm_consttime_is_mem_equal(prev_spdm_request,
159 : &spdm_key_init_update_operation,
160 : sizeof(spdm_key_update_request_t))) {
161 2 : return libspdm_generate_error_response(spdm_context,
162 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
163 : response_size, response);
164 : }
165 :
166 3 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
167 : "libspdm_create_update_session_data_key[%x] Requester\n",
168 : session_id));
169 3 : result = libspdm_create_update_session_data_key(
170 : session_info->secured_message_context,
171 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
172 3 : if (!result) {
173 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
174 : }
175 3 : libspdm_trigger_key_update_callback(
176 : spdm_context, session_id, LIBSPDM_KEY_UPDATE_OPERATION_CREATE_UPDATE,
177 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
178 :
179 3 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
180 : "libspdm_create_update_session_data_key[%x] Responder\n",
181 : session_id));
182 3 : result = libspdm_create_update_session_data_key(
183 : session_info->secured_message_context,
184 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
185 3 : if (!result) {
186 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
187 : }
188 3 : libspdm_trigger_key_update_callback(
189 : spdm_context, session_id, LIBSPDM_KEY_UPDATE_OPERATION_CREATE_UPDATE,
190 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
191 :
192 : /* We can commit to Responder key. */
193 3 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
194 : "libspdm_activate_update_session_data_key[%x] Responder new\n",
195 : session_id));
196 3 : result = libspdm_activate_update_session_data_key(
197 : session_info->secured_message_context,
198 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, true);
199 3 : if (!result) {
200 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
201 : }
202 3 : libspdm_trigger_key_update_callback(
203 : spdm_context, session_id, LIBSPDM_KEY_UPDATE_OPERATION_COMMIT_UPDATE,
204 : LIBSPDM_KEY_UPDATE_ACTION_RESPONDER);
205 :
206 : /*save the last update operation*/
207 3 : libspdm_copy_mem(prev_spdm_request, sizeof(spdm_key_update_request_t),
208 : spdm_request, request_size);
209 3 : break;
210 5 : case SPDM_KEY_UPDATE_OPERATIONS_TABLE_VERIFY_NEW_KEY:
211 5 : if(prev_spdm_request->header.param1 !=
212 4 : SPDM_KEY_UPDATE_OPERATIONS_TABLE_UPDATE_KEY &&
213 4 : prev_spdm_request->header.param1 !=
214 : SPDM_KEY_UPDATE_OPERATIONS_TABLE_UPDATE_ALL_KEYS) {
215 3 : return libspdm_generate_error_response(spdm_context,
216 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
217 : response_size, response);
218 : }
219 : /* With Requester key verified, we can discard backups. */
220 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
221 : "libspdm_activate_update_session_data_key[%x] Requester new\n",
222 : session_id));
223 2 : result = libspdm_activate_update_session_data_key(
224 : session_info->secured_message_context,
225 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER, true);
226 2 : if (!result) {
227 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
228 : }
229 2 : libspdm_trigger_key_update_callback(
230 : spdm_context, session_id, LIBSPDM_KEY_UPDATE_OPERATION_COMMIT_UPDATE,
231 : LIBSPDM_KEY_UPDATE_ACTION_REQUESTER);
232 :
233 : /*clear last_key_update_request*/
234 2 : libspdm_zero_mem (prev_spdm_request, sizeof(spdm_key_update_request_t));
235 2 : break;
236 1 : default:
237 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "espurious case\n"));
238 1 : return libspdm_generate_error_response(spdm_context,
239 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
240 : response_size, response);
241 : }
242 :
243 9 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
244 9 : spdm_request->header.request_response_code);
245 :
246 9 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_key_update_response_t));
247 9 : *response_size = sizeof(spdm_key_update_response_t);
248 9 : libspdm_zero_mem(response, *response_size);
249 9 : spdm_response = response;
250 :
251 9 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
252 9 : spdm_response->header.request_response_code = SPDM_KEY_UPDATE_ACK;
253 9 : spdm_response->header.param1 = spdm_request->header.param1;
254 9 : spdm_response->header.param2 = spdm_request->header.param2;
255 :
256 9 : return LIBSPDM_STATUS_SUCCESS;
257 : }
258 :
259 : #endif /* (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP) || (LIBSPDM_ENABLE_CAPABILITY_PSK_CAP) */
|