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