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