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 :
168 : #if LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP
169 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
170 9 : if (libspdm_is_capabilities_flag_supported(
171 : spdm_context, false,
172 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP,
173 0 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP) &&
174 0 : libspdm_is_capabilities_flag_supported(
175 : spdm_context, false,
176 0 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHAL_CAP, 0) &&
177 0 : (libspdm_is_capabilities_flag_supported(
178 : spdm_context, false,
179 0 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, 0) ||
180 0 : libspdm_is_capabilities_flag_supported(
181 : spdm_context, false,
182 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP, 0))) {
183 0 : if (libspdm_challenge_start_mut_auth(spdm_context,
184 0 : spdm_context->connection_info.version,
185 : slot_id,
186 : request_context_size,
187 : request_context)) {
188 0 : auth_attribute |= SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ;
189 0 : libspdm_init_basic_mut_auth_encap_state(spdm_context);
190 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
191 : "Basic mutual authentication is a deprecated feature.\n"));
192 : }
193 : }
194 : }
195 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP */
196 :
197 9 : spdm_response->header.param1 = auth_attribute;
198 :
199 9 : if (slot_id == 0xFF) {
200 1 : spdm_response->header.param2 = 0;
201 : } else {
202 8 : slot_mask = libspdm_get_cert_slot_mask(spdm_context);
203 8 : if (slot_mask != 0) {
204 8 : spdm_response->header.param2 = slot_mask;
205 : } else {
206 0 : return libspdm_generate_error_response(
207 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
208 : 0, response_size, response);
209 : }
210 : }
211 :
212 9 : ptr = (void *)(spdm_response + 1);
213 9 : if (slot_id == 0xFF) {
214 1 : result = libspdm_generate_public_key_hash(spdm_context, ptr);
215 : } else {
216 8 : result = libspdm_generate_cert_chain_hash(spdm_context, slot_id, ptr);
217 : }
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 += hash_size;
224 :
225 9 : result = libspdm_get_random_number(SPDM_NONCE_SIZE, ptr);
226 9 : if (!result) {
227 0 : return libspdm_generate_error_response(spdm_context,
228 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
229 : response_size, response);
230 : }
231 9 : ptr += SPDM_NONCE_SIZE;
232 :
233 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
234 9 : if (libspdm_is_capabilities_flag_supported(
235 2 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) &&
236 2 : ((spdm_request->header.param2 == SPDM_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH) ||
237 1 : (spdm_request->header.param2 == SPDM_REQUEST_ALL_MEASUREMENTS_HASH))) {
238 2 : result = libspdm_generate_measurement_summary_hash(
239 : spdm_context,
240 2 : spdm_context->connection_info.version,
241 : spdm_context->connection_info.algorithm.base_hash_algo,
242 2 : spdm_context->connection_info.algorithm.measurement_spec,
243 : spdm_context->connection_info.algorithm.measurement_hash_algo,
244 2 : spdm_request->header.param2,
245 : ptr,
246 : measurement_summary_hash_size);
247 :
248 2 : if (!result) {
249 0 : return libspdm_generate_error_response(spdm_context,
250 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
251 : response_size, response);
252 : }
253 : }
254 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP */
255 :
256 9 : ptr += measurement_summary_hash_size;
257 :
258 9 : opaque_data_size = *response_size - (sizeof(spdm_challenge_auth_response_t) + hash_size +
259 9 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
260 9 : sizeof(uint16_t) + signature_size);
261 9 : opaque_data =
262 9 : (uint8_t*)response + sizeof(spdm_challenge_auth_response_t) + hash_size + SPDM_NONCE_SIZE +
263 9 : measurement_summary_hash_size + sizeof(uint16_t);
264 :
265 9 : if ((libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) &&
266 1 : ((spdm_context->connection_info.algorithm.other_params_support &
267 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE)) {
268 1 : opaque_data_size = 0;
269 : } else {
270 8 : result = libspdm_challenge_opaque_data(
271 : spdm_context,
272 8 : spdm_context->connection_info.version,
273 : slot_id,
274 : request_context_size,
275 : request_context,
276 : opaque_data, &opaque_data_size);
277 8 : if (!result) {
278 0 : return libspdm_generate_error_response(
279 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
280 : 0, response_size, response);
281 : }
282 : }
283 :
284 : /*write opaque_data_size*/
285 9 : libspdm_write_uint16 (ptr, (uint16_t)opaque_data_size);
286 9 : ptr += sizeof(uint16_t);
287 :
288 : /*the opaque_data is stored by libspdm_challenge_opaque_data*/
289 9 : ptr += opaque_data_size;
290 :
291 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
292 1 : libspdm_copy_mem(ptr, SPDM_REQ_CONTEXT_SIZE,
293 1 : spdm_request + 1, SPDM_REQ_CONTEXT_SIZE);
294 1 : ptr += SPDM_REQ_CONTEXT_SIZE;
295 : }
296 :
297 : /*get actual response size*/
298 9 : spdm_response_size =
299 : sizeof(spdm_challenge_auth_response_t) + hash_size +
300 9 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
301 9 : sizeof(uint16_t) + opaque_data_size + signature_size;
302 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
303 1 : spdm_response_size += SPDM_REQ_CONTEXT_SIZE;
304 : }
305 :
306 9 : LIBSPDM_ASSERT(*response_size >= spdm_response_size);
307 :
308 9 : *response_size = spdm_response_size;
309 :
310 : /* Calc Sign*/
311 :
312 9 : status = libspdm_append_message_c(spdm_context, spdm_request, spdm_request_size);
313 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
314 0 : return libspdm_generate_error_response(spdm_context,
315 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
316 : response_size, response);
317 : }
318 :
319 9 : status = libspdm_append_message_c(spdm_context, spdm_response,
320 9 : (size_t)ptr - (size_t)spdm_response);
321 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
322 0 : libspdm_reset_message_c(spdm_context);
323 0 : return libspdm_generate_error_response(spdm_context,
324 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
325 : response_size, response);
326 : }
327 9 : result = libspdm_generate_challenge_auth_signature(spdm_context, false, slot_id, ptr);
328 9 : if (!result) {
329 0 : libspdm_reset_message_c(spdm_context);
330 0 : return libspdm_generate_error_response(
331 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
332 : 0, response_size, response);
333 : }
334 9 : ptr += signature_size;
335 :
336 9 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ) == 0) {
337 9 : libspdm_set_connection_state(spdm_context,
338 : LIBSPDM_CONNECTION_STATE_AUTHENTICATED);
339 : }
340 :
341 9 : libspdm_reset_message_b(spdm_context);
342 9 : libspdm_reset_message_c(spdm_context);
343 :
344 9 : return LIBSPDM_STATUS_SUCCESS;
345 : }
346 :
347 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP */
|