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 :
9 :
10 : #if LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP
11 :
12 19 : libspdm_return_t libspdm_get_response_challenge_auth(libspdm_context_t *spdm_context,
13 : size_t request_size,
14 : const void *request,
15 : size_t *response_size,
16 : void *response)
17 : {
18 : const spdm_challenge_request_t *spdm_request;
19 : size_t spdm_request_size;
20 : spdm_challenge_auth_response_t *spdm_response;
21 : bool result;
22 : size_t signature_size;
23 : uint8_t slot_id;
24 : uint32_t hash_size;
25 : uint8_t *measurement_summary_hash;
26 : uint32_t measurement_summary_hash_size;
27 : uint8_t *ptr;
28 : uint8_t auth_attribute;
29 : libspdm_return_t status;
30 : uint8_t slot_mask;
31 : uint8_t *opaque_data;
32 : size_t opaque_data_size;
33 : size_t spdm_response_size;
34 :
35 19 : spdm_request = request;
36 :
37 : /* -=[Check Parameters Phase]=- */
38 19 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_CHALLENGE);
39 :
40 19 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
41 0 : return libspdm_generate_error_response(spdm_context,
42 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
43 : response_size, response);
44 : }
45 19 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
46 3 : return libspdm_responder_handle_response_state(
47 : spdm_context,
48 3 : spdm_request->header.request_response_code,
49 : response_size, response);
50 : }
51 16 : if (spdm_context->last_spdm_request_session_id_valid) {
52 1 : return libspdm_generate_error_response(spdm_context,
53 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
54 : response_size, response);
55 : }
56 15 : if (!libspdm_is_capabilities_flag_supported(
57 : spdm_context, false, 0,
58 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP)) {
59 1 : return libspdm_generate_error_response(
60 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
61 : SPDM_CHALLENGE, response_size, response);
62 : }
63 14 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
64 1 : return libspdm_generate_error_response(spdm_context,
65 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
66 : 0, response_size, response);
67 : }
68 :
69 13 : if (request_size < sizeof(spdm_challenge_request_t)) {
70 0 : return libspdm_generate_error_response(spdm_context,
71 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
72 : response_size, response);
73 : }
74 13 : spdm_request_size = sizeof(spdm_challenge_request_t);
75 13 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
76 2 : if (request_size < sizeof(spdm_challenge_request_t) + SPDM_REQ_CONTEXT_SIZE) {
77 0 : return libspdm_generate_error_response(spdm_context,
78 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
79 : response_size, response);
80 : }
81 2 : spdm_request_size += SPDM_REQ_CONTEXT_SIZE;
82 : }
83 13 : if (spdm_request->header.param2 > 0) {
84 3 : if (!libspdm_is_capabilities_flag_supported(
85 : spdm_context, false, 0,
86 2 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) ||
87 2 : (spdm_context->connection_info.algorithm.measurement_spec == 0) ||
88 2 : (spdm_context->connection_info.algorithm.measurement_hash_algo == 0) ) {
89 1 : return libspdm_generate_error_response (spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
90 : 0, response_size, response);
91 : }
92 : }
93 :
94 12 : slot_id = spdm_request->header.param1;
95 :
96 12 : if ((slot_id != 0xFF) && (slot_id >= SPDM_MAX_SLOT_COUNT)) {
97 1 : return libspdm_generate_error_response(spdm_context,
98 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
99 : response_size, response);
100 : }
101 :
102 11 : if (slot_id != 0xFF) {
103 10 : if (spdm_context->local_context.local_cert_chain_provision[slot_id] == NULL) {
104 1 : return libspdm_generate_error_response(
105 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
106 : 0, response_size, response);
107 : }
108 : } else {
109 1 : if (spdm_context->local_context.local_public_key_provision == NULL) {
110 0 : return libspdm_generate_error_response(
111 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
112 : 0, response_size, response);
113 : }
114 : }
115 :
116 10 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
117 2 : spdm_context->connection_info.multi_key_conn_rsp &&
118 : (slot_id != 0xFF)) {
119 1 : if ((spdm_context->local_context.local_key_usage_bit_mask[slot_id] &
120 : SPDM_KEY_USAGE_BIT_MASK_CHALLENGE_USE) == 0) {
121 1 : return libspdm_generate_error_response(
122 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
123 : 0, response_size, response);
124 : }
125 : }
126 :
127 9 : if (spdm_context->connection_info.algorithm.pqc_asym_algo != 0) {
128 0 : signature_size = libspdm_get_pqc_asym_signature_size(
129 : spdm_context->connection_info.algorithm.pqc_asym_algo);
130 : } else {
131 9 : signature_size = libspdm_get_asym_signature_size(
132 : spdm_context->connection_info.algorithm.base_asym_algo);
133 : }
134 9 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
135 9 : measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
136 9 : spdm_context, false, spdm_request->header.param2);
137 9 : if ((measurement_summary_hash_size == 0) &&
138 7 : (spdm_request->header.param2 != SPDM_CHALLENGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH)) {
139 0 : return libspdm_generate_error_response(spdm_context,
140 : SPDM_ERROR_CODE_INVALID_REQUEST,
141 : 0, response_size, response);
142 : }
143 :
144 : /* response_size should be large enough to hold a challenge response without opaque data. */
145 9 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_challenge_auth_response_t) + hash_size +
146 : SPDM_NONCE_SIZE + measurement_summary_hash_size + sizeof(uint16_t) +
147 : SPDM_REQ_CONTEXT_SIZE + signature_size);
148 :
149 9 : libspdm_zero_mem(response, *response_size);
150 9 : spdm_response = response;
151 :
152 9 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
153 9 : spdm_request->header.request_response_code);
154 :
155 9 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
156 9 : spdm_response->header.request_response_code = SPDM_CHALLENGE_AUTH;
157 9 : auth_attribute = (uint8_t)(slot_id & 0xF);
158 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
159 9 : if (libspdm_is_capabilities_flag_supported(
160 : spdm_context, false,
161 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP,
162 0 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP) &&
163 0 : libspdm_is_capabilities_flag_supported(
164 : spdm_context, false,
165 0 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHAL_CAP, 0) &&
166 0 : (libspdm_is_capabilities_flag_supported(
167 : spdm_context, false,
168 0 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, 0) ||
169 0 : libspdm_is_capabilities_flag_supported(
170 : spdm_context, false,
171 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP, 0))) {
172 0 : if (spdm_context->local_context.basic_mut_auth_requested) {
173 0 : auth_attribute =
174 : (uint8_t)(auth_attribute |
175 : SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ);
176 : }
177 : }
178 9 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ) != 0) {
179 : #if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_SEND_CHALLENGE_SUPPORT)
180 0 : libspdm_init_basic_mut_auth_encap_state(spdm_context);
181 : #else
182 : auth_attribute =
183 : (uint8_t)(auth_attribute &
184 : ~SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ);
185 : #endif
186 : }
187 : }
188 :
189 9 : spdm_response->header.param1 = auth_attribute;
190 :
191 9 : if (slot_id == 0xFF) {
192 1 : spdm_response->header.param2 = 0;
193 : } else {
194 8 : slot_mask = libspdm_get_cert_slot_mask(spdm_context);
195 8 : if (slot_mask != 0) {
196 8 : spdm_response->header.param2 = slot_mask;
197 : } else {
198 0 : return libspdm_generate_error_response(
199 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
200 : 0, response_size, response);
201 : }
202 : }
203 :
204 9 : ptr = (void *)(spdm_response + 1);
205 9 : if (slot_id == 0xFF) {
206 1 : result = libspdm_generate_public_key_hash(spdm_context, ptr);
207 : } else {
208 8 : result = libspdm_generate_cert_chain_hash(spdm_context, slot_id, ptr);
209 : }
210 9 : if (!result) {
211 0 : return libspdm_generate_error_response(spdm_context,
212 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
213 : response_size, response);
214 : }
215 9 : ptr += hash_size;
216 :
217 9 : result = libspdm_get_random_number(SPDM_NONCE_SIZE, ptr);
218 9 : if (!result) {
219 0 : return libspdm_generate_error_response(spdm_context,
220 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
221 : response_size, response);
222 : }
223 9 : ptr += SPDM_NONCE_SIZE;
224 :
225 9 : measurement_summary_hash = ptr;
226 :
227 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
228 9 : if (libspdm_is_capabilities_flag_supported(
229 2 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) &&
230 2 : ((spdm_request->header.param2 == SPDM_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH) ||
231 1 : (spdm_request->header.param2 == SPDM_REQUEST_ALL_MEASUREMENTS_HASH))) {
232 2 : result = libspdm_generate_measurement_summary_hash(
233 : #if LIBSPDM_HAL_PASS_SPDM_CONTEXT
234 : spdm_context,
235 : #endif
236 2 : spdm_context->connection_info.version,
237 : spdm_context->connection_info.algorithm.base_hash_algo,
238 2 : spdm_context->connection_info.algorithm.measurement_spec,
239 : spdm_context->connection_info.algorithm.measurement_hash_algo,
240 2 : spdm_request->header.param2,
241 : ptr,
242 : measurement_summary_hash_size);
243 :
244 2 : if (!result) {
245 0 : return libspdm_generate_error_response(spdm_context,
246 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
247 : response_size, response);
248 : }
249 : }
250 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP */
251 :
252 9 : ptr += measurement_summary_hash_size;
253 :
254 9 : opaque_data_size = *response_size - (sizeof(spdm_challenge_auth_response_t) + hash_size +
255 9 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
256 9 : sizeof(uint16_t) + signature_size);
257 9 : opaque_data =
258 9 : (uint8_t*)response + sizeof(spdm_challenge_auth_response_t) + hash_size + SPDM_NONCE_SIZE +
259 9 : measurement_summary_hash_size + sizeof(uint16_t);
260 :
261 9 : if ((libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) &&
262 1 : ((spdm_context->connection_info.algorithm.other_params_support &
263 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE)) {
264 1 : opaque_data_size = 0;
265 : } else {
266 8 : result = libspdm_challenge_opaque_data(
267 : #if LIBSPDM_HAL_PASS_SPDM_CONTEXT
268 : spdm_context,
269 : #endif
270 8 : spdm_context->connection_info.version,
271 : slot_id,
272 : measurement_summary_hash, measurement_summary_hash_size,
273 : opaque_data, &opaque_data_size);
274 8 : if (!result) {
275 0 : return libspdm_generate_error_response(
276 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
277 : 0, response_size, response);
278 : }
279 : }
280 :
281 : /*write opaque_data_size*/
282 9 : libspdm_write_uint16 (ptr, (uint16_t)opaque_data_size);
283 9 : ptr += sizeof(uint16_t);
284 :
285 : /*the opaque_data is stored by libspdm_challenge_opaque_data*/
286 9 : ptr += opaque_data_size;
287 :
288 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
289 1 : libspdm_copy_mem(ptr, SPDM_REQ_CONTEXT_SIZE,
290 1 : spdm_request + 1, SPDM_REQ_CONTEXT_SIZE);
291 1 : ptr += SPDM_REQ_CONTEXT_SIZE;
292 : }
293 :
294 : /*get actual response size*/
295 9 : spdm_response_size =
296 : sizeof(spdm_challenge_auth_response_t) + hash_size +
297 9 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
298 9 : sizeof(uint16_t) + opaque_data_size + signature_size;
299 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
300 1 : spdm_response_size += SPDM_REQ_CONTEXT_SIZE;
301 : }
302 :
303 9 : LIBSPDM_ASSERT(*response_size >= spdm_response_size);
304 :
305 9 : *response_size = spdm_response_size;
306 :
307 : /* Calc Sign*/
308 :
309 9 : status = libspdm_append_message_c(spdm_context, spdm_request, spdm_request_size);
310 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
311 0 : return libspdm_generate_error_response(spdm_context,
312 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
313 : response_size, response);
314 : }
315 :
316 9 : status = libspdm_append_message_c(spdm_context, spdm_response,
317 9 : (size_t)ptr - (size_t)spdm_response);
318 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
319 0 : libspdm_reset_message_c(spdm_context);
320 0 : return libspdm_generate_error_response(spdm_context,
321 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
322 : response_size, response);
323 : }
324 9 : result = libspdm_generate_challenge_auth_signature(spdm_context, false, ptr);
325 9 : if (!result) {
326 0 : libspdm_reset_message_c(spdm_context);
327 0 : return libspdm_generate_error_response(
328 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
329 : 0, response_size, response);
330 : }
331 9 : ptr += signature_size;
332 :
333 9 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ) == 0) {
334 9 : libspdm_set_connection_state(spdm_context,
335 : LIBSPDM_CONNECTION_STATE_AUTHENTICATED);
336 : }
337 :
338 9 : libspdm_reset_message_b(spdm_context);
339 9 : libspdm_reset_message_c(spdm_context);
340 :
341 9 : return LIBSPDM_STATUS_SUCCESS;
342 : }
343 :
344 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP */
|