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 : signature_size = libspdm_get_asym_signature_size(
128 : spdm_context->connection_info.algorithm.base_asym_algo);
129 9 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
130 9 : measurement_summary_hash_size = libspdm_get_measurement_summary_hash_size(
131 9 : spdm_context, false, spdm_request->header.param2);
132 9 : if ((measurement_summary_hash_size == 0) &&
133 7 : (spdm_request->header.param2 != SPDM_CHALLENGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH)) {
134 0 : return libspdm_generate_error_response(spdm_context,
135 : SPDM_ERROR_CODE_INVALID_REQUEST,
136 : 0, response_size, response);
137 : }
138 :
139 : /* response_size should be large enough to hold a challenge response without opaque data. */
140 9 : LIBSPDM_ASSERT(*response_size >= sizeof(spdm_challenge_auth_response_t) + hash_size +
141 : SPDM_NONCE_SIZE + measurement_summary_hash_size + sizeof(uint16_t) +
142 : SPDM_REQ_CONTEXT_SIZE + signature_size);
143 :
144 9 : libspdm_zero_mem(response, *response_size);
145 9 : spdm_response = response;
146 :
147 9 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
148 9 : spdm_request->header.request_response_code);
149 :
150 9 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
151 9 : spdm_response->header.request_response_code = SPDM_CHALLENGE_AUTH;
152 9 : auth_attribute = (uint8_t)(slot_id & 0xF);
153 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_11) {
154 9 : if (libspdm_is_capabilities_flag_supported(
155 : spdm_context, false,
156 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP,
157 0 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP) &&
158 0 : libspdm_is_capabilities_flag_supported(
159 : spdm_context, false,
160 0 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHAL_CAP, 0) &&
161 0 : (libspdm_is_capabilities_flag_supported(
162 : spdm_context, false,
163 0 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, 0) ||
164 0 : libspdm_is_capabilities_flag_supported(
165 : spdm_context, false,
166 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP, 0))) {
167 0 : if (spdm_context->local_context.basic_mut_auth_requested) {
168 0 : auth_attribute =
169 : (uint8_t)(auth_attribute |
170 : SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ);
171 : }
172 : }
173 9 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ) != 0) {
174 : #if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (LIBSPDM_SEND_CHALLENGE_SUPPORT)
175 0 : libspdm_init_basic_mut_auth_encap_state(spdm_context);
176 : #else
177 : auth_attribute =
178 : (uint8_t)(auth_attribute &
179 : ~SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ);
180 : #endif
181 : }
182 : }
183 :
184 9 : spdm_response->header.param1 = auth_attribute;
185 :
186 9 : if (slot_id == 0xFF) {
187 1 : spdm_response->header.param2 = 0;
188 : } else {
189 8 : slot_mask = libspdm_get_cert_slot_mask(spdm_context);
190 8 : if (slot_mask != 0) {
191 8 : spdm_response->header.param2 = slot_mask;
192 : } else {
193 0 : return libspdm_generate_error_response(
194 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
195 : 0, response_size, response);
196 : }
197 : }
198 :
199 9 : ptr = (void *)(spdm_response + 1);
200 9 : if (slot_id == 0xFF) {
201 1 : result = libspdm_generate_public_key_hash(spdm_context, ptr);
202 : } else {
203 8 : result = libspdm_generate_cert_chain_hash(spdm_context, slot_id, ptr);
204 : }
205 9 : if (!result) {
206 0 : return libspdm_generate_error_response(spdm_context,
207 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
208 : response_size, response);
209 : }
210 9 : ptr += hash_size;
211 :
212 9 : result = libspdm_get_random_number(SPDM_NONCE_SIZE, ptr);
213 9 : if (!result) {
214 0 : return libspdm_generate_error_response(spdm_context,
215 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
216 : response_size, response);
217 : }
218 9 : ptr += SPDM_NONCE_SIZE;
219 :
220 9 : measurement_summary_hash = ptr;
221 :
222 : #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP
223 9 : if (libspdm_is_capabilities_flag_supported(
224 2 : spdm_context, false, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP) &&
225 2 : ((spdm_request->header.param2 == SPDM_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH) ||
226 1 : (spdm_request->header.param2 == SPDM_REQUEST_ALL_MEASUREMENTS_HASH))) {
227 2 : result = libspdm_generate_measurement_summary_hash(
228 : #if LIBSPDM_HAL_PASS_SPDM_CONTEXT
229 : spdm_context,
230 : #endif
231 2 : spdm_context->connection_info.version,
232 : spdm_context->connection_info.algorithm.base_hash_algo,
233 2 : spdm_context->connection_info.algorithm.measurement_spec,
234 : spdm_context->connection_info.algorithm.measurement_hash_algo,
235 2 : spdm_request->header.param2,
236 : ptr,
237 : measurement_summary_hash_size);
238 :
239 2 : if (!result) {
240 0 : return libspdm_generate_error_response(spdm_context,
241 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
242 : response_size, response);
243 : }
244 : }
245 : #endif /* LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP */
246 :
247 9 : ptr += measurement_summary_hash_size;
248 :
249 9 : opaque_data_size = *response_size - (sizeof(spdm_challenge_auth_response_t) + hash_size +
250 9 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
251 9 : sizeof(uint16_t) + signature_size);
252 9 : opaque_data =
253 9 : (uint8_t*)response + sizeof(spdm_challenge_auth_response_t) + hash_size + SPDM_NONCE_SIZE +
254 9 : measurement_summary_hash_size + sizeof(uint16_t);
255 :
256 9 : if ((libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_12) &&
257 1 : ((spdm_context->connection_info.algorithm.other_params_support &
258 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE)) {
259 1 : opaque_data_size = 0;
260 : } else {
261 8 : result = libspdm_challenge_opaque_data(
262 : #if LIBSPDM_HAL_PASS_SPDM_CONTEXT
263 : spdm_context,
264 : #endif
265 8 : spdm_context->connection_info.version,
266 : slot_id,
267 : measurement_summary_hash, measurement_summary_hash_size,
268 : opaque_data, &opaque_data_size);
269 8 : if (!result) {
270 0 : return libspdm_generate_error_response(
271 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
272 : 0, response_size, response);
273 : }
274 : }
275 :
276 : /*write opaque_data_size*/
277 9 : libspdm_write_uint16 (ptr, (uint16_t)opaque_data_size);
278 9 : ptr += sizeof(uint16_t);
279 :
280 : /*the opaque_data is stored by libspdm_challenge_opaque_data*/
281 9 : ptr += opaque_data_size;
282 :
283 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
284 1 : libspdm_copy_mem(ptr, SPDM_REQ_CONTEXT_SIZE,
285 1 : spdm_request + 1, SPDM_REQ_CONTEXT_SIZE);
286 1 : ptr += SPDM_REQ_CONTEXT_SIZE;
287 : }
288 :
289 : /*get actual response size*/
290 9 : spdm_response_size =
291 : sizeof(spdm_challenge_auth_response_t) + hash_size +
292 9 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
293 9 : sizeof(uint16_t) + opaque_data_size + signature_size;
294 9 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
295 1 : spdm_response_size += SPDM_REQ_CONTEXT_SIZE;
296 : }
297 :
298 9 : LIBSPDM_ASSERT(*response_size >= spdm_response_size);
299 :
300 9 : *response_size = spdm_response_size;
301 :
302 : /* Calc Sign*/
303 :
304 9 : status = libspdm_append_message_c(spdm_context, spdm_request, spdm_request_size);
305 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
306 0 : return libspdm_generate_error_response(spdm_context,
307 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
308 : response_size, response);
309 : }
310 :
311 9 : status = libspdm_append_message_c(spdm_context, spdm_response,
312 9 : (size_t)ptr - (size_t)spdm_response);
313 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
314 0 : libspdm_reset_message_c(spdm_context);
315 0 : return libspdm_generate_error_response(spdm_context,
316 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
317 : response_size, response);
318 : }
319 9 : result = libspdm_generate_challenge_auth_signature(spdm_context, false, ptr);
320 9 : if (!result) {
321 0 : libspdm_reset_message_c(spdm_context);
322 0 : return libspdm_generate_error_response(
323 : spdm_context, SPDM_ERROR_CODE_UNSPECIFIED,
324 : 0, response_size, response);
325 : }
326 9 : ptr += signature_size;
327 :
328 9 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ) == 0) {
329 9 : libspdm_set_connection_state(spdm_context,
330 : LIBSPDM_CONNECTION_STATE_AUTHENTICATED);
331 : }
332 :
333 9 : libspdm_reset_message_b(spdm_context);
334 9 : libspdm_reset_message_c(spdm_context);
335 :
336 9 : return LIBSPDM_STATUS_SUCCESS;
337 : }
338 :
339 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP */
|