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