Branch data 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_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && \
10 : : (LIBSPDM_SEND_CHALLENGE_SUPPORT)
11 : :
12 : 9 : libspdm_return_t libspdm_get_encap_request_challenge(void *context,
13 : : uint8_t req_slot_id,
14 : : const void *requester_context,
15 : : size_t *encap_request_size,
16 : : void *encap_request)
17 : : {
18 : : libspdm_encap_context_t *encap_context;
19 : : libspdm_context_t *spdm_context;
20 : : spdm_challenge_request_t *spdm_request;
21 : : size_t spdm_request_size;
22 : : libspdm_return_t status;
23 : :
24 : 9 : spdm_context = context;
25 : :
26 [ + + + + ]: 9 : if ((req_slot_id >= SPDM_MAX_SLOT_COUNT) && (req_slot_id != 0xFF)) {
27 : : /* 0xFF designates the Requester's provisioned public key. Any other slot indexes per-slot
28 : : * state of SPDM_MAX_SLOT_COUNT entries, which CHALLENGE_AUTH is verified against. */
29 : 3 : return LIBSPDM_STATUS_INVALID_PARAMETER;
30 : : }
31 : :
32 : 6 : encap_context = libspdm_get_encap_context_via_last_request(spdm_context);
33 : :
34 : 6 : encap_context->last_encap_request_size = 0;
35 : :
36 [ + + ]: 6 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
37 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
38 : : }
39 : :
40 [ - + ]: 5 : if (!libspdm_is_capabilities_flag_supported(
41 : : spdm_context, false,
42 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHAL_CAP, 0)) {
43 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
44 : : }
45 : :
46 : 5 : spdm_request_size = sizeof(spdm_challenge_request_t);
47 [ + + ]: 5 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_13) {
48 : 2 : spdm_request_size = sizeof(spdm_challenge_request_t) + SPDM_REQ_CONTEXT_SIZE;
49 : : }
50 : :
51 [ - + ]: 5 : if (*encap_request_size < spdm_request_size) {
52 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
53 : : }
54 : 5 : *encap_request_size = spdm_request_size;
55 : :
56 : 5 : spdm_request = encap_request;
57 : :
58 : 5 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
59 : 5 : spdm_request->header.request_response_code = SPDM_CHALLENGE;
60 : 5 : spdm_request->header.param1 = req_slot_id;
61 : 5 : spdm_request->header.param2 = SPDM_CHALLENGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH;
62 [ - + ]: 5 : if (!libspdm_get_random_number(SPDM_NONCE_SIZE, spdm_request->nonce)) {
63 : 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
64 : : }
65 : 5 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap RequesterNonce - "));
66 : 5 : LIBSPDM_INTERNAL_DUMP_DATA(spdm_request->nonce, SPDM_NONCE_SIZE);
67 : 5 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
68 [ + + ]: 5 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
69 : : /* Record the RequesterContext, as the CHALLENGE_AUTH response is checked against it. */
70 [ + + ]: 2 : if (requester_context == NULL) {
71 : 1 : libspdm_zero_mem(encap_context->req_context, SPDM_REQ_CONTEXT_SIZE);
72 : : } else {
73 : 1 : libspdm_copy_mem(encap_context->req_context, SPDM_REQ_CONTEXT_SIZE,
74 : : requester_context, SPDM_REQ_CONTEXT_SIZE);
75 : : }
76 : 2 : libspdm_copy_mem(spdm_request + 1, SPDM_REQ_CONTEXT_SIZE,
77 : 2 : encap_context->req_context, SPDM_REQ_CONTEXT_SIZE);
78 : 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap RequesterContext - "));
79 : 2 : LIBSPDM_INTERNAL_DUMP_DATA((uint8_t *)(spdm_request + 1), SPDM_REQ_CONTEXT_SIZE);
80 : 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
81 : : }
82 : :
83 : : /* Cache data */
84 : 5 : status = libspdm_append_message_mut_c(spdm_context, spdm_request, spdm_request_size);
85 [ - + ]: 5 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
86 : 0 : return LIBSPDM_STATUS_BUFFER_FULL;
87 : : }
88 : :
89 : : /* Record the slot that was requested so that the CHALLENGE_AUTH response can be verified
90 : : * against it. */
91 : 5 : encap_context->req_slot_id = req_slot_id;
92 : 5 : libspdm_copy_mem(&encap_context->last_encap_request_header,
93 : : sizeof(encap_context->last_encap_request_header),
94 : 5 : &spdm_request->header, sizeof(spdm_message_header_t));
95 : 5 : encap_context->last_encap_request_size = spdm_request_size;
96 : :
97 : 5 : return LIBSPDM_STATUS_SUCCESS;
98 : : }
99 : :
100 : 9 : libspdm_return_t libspdm_process_encap_response_challenge_auth(
101 : : libspdm_context_t *spdm_context, size_t encap_response_size,
102 : : const void *encap_response, bool *need_continue)
103 : : {
104 : : libspdm_encap_context_t *encap_context;
105 : : bool result;
106 : : const spdm_challenge_auth_response_t *spdm_response;
107 : : size_t spdm_response_size;
108 : : const uint8_t *ptr;
109 : : const void *cert_chain_hash;
110 : : size_t hash_size;
111 : : uint32_t measurement_summary_hash_size;
112 : : uint16_t opaque_length;
113 : : const void *signature;
114 : : size_t signature_size;
115 : : uint8_t auth_attribute;
116 : : libspdm_return_t status;
117 : :
118 : 9 : spdm_response = encap_response;
119 : 9 : spdm_response_size = encap_response_size;
120 : :
121 [ - + ]: 9 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
122 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
123 : : }
124 [ - + ]: 9 : if (spdm_response->header.spdm_version != libspdm_get_connection_version (spdm_context)) {
125 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
126 : : }
127 [ + + ]: 9 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
128 : 2 : status = libspdm_handle_encap_error_response_main(spdm_response->header.param1);
129 [ + - ]: 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
130 : 2 : return status;
131 : : }
132 [ + + ]: 7 : } else if (spdm_response->header.request_response_code != SPDM_CHALLENGE_AUTH) {
133 : 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
134 : : }
135 [ - + ]: 6 : if (spdm_response_size < sizeof(spdm_challenge_auth_response_t)) {
136 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
137 : : }
138 [ + + ]: 6 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
139 [ - + ]: 1 : if (spdm_response_size < sizeof(spdm_challenge_auth_response_t) + SPDM_REQ_CONTEXT_SIZE) {
140 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
141 : : }
142 : : }
143 : :
144 : 6 : auth_attribute = spdm_response->header.param1;
145 : 6 : encap_context = libspdm_get_encap_context_via_last_request(spdm_context);
146 : :
147 [ + + ]: 6 : if (encap_context->req_slot_id == 0xFF) {
148 [ - + ]: 1 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_SLOT_ID_MASK) != 0xF) {
149 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
150 : : }
151 [ - + ]: 1 : if (spdm_response->header.param2 != 0) {
152 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
153 : : }
154 : : } else {
155 : 5 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_SLOT_ID_MASK) !=
156 [ - + ]: 5 : encap_context->req_slot_id) {
157 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
158 : : }
159 [ + + ]: 5 : if ((spdm_response->header.param2 & (1 << encap_context->req_slot_id)) == 0) {
160 : 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
161 : : }
162 : : }
163 : :
164 [ - + ]: 5 : if ((auth_attribute & SPDM_CHALLENGE_AUTH_RESPONSE_ATTRIBUTE_BASIC_MUT_AUTH_REQ) != 0) {
165 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
166 : : }
167 : :
168 : 5 : hash_size = libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
169 [ - + ]: 5 : if (spdm_context->connection_info.algorithm.req_pqc_asym_alg != 0) {
170 : 0 : signature_size = libspdm_get_req_pqc_asym_signature_size(
171 : : spdm_context->connection_info.algorithm.req_pqc_asym_alg);
172 : : } else {
173 : 5 : signature_size = libspdm_get_req_asym_signature_size(
174 : 5 : spdm_context->connection_info.algorithm.req_base_asym_alg);
175 : : }
176 : 5 : measurement_summary_hash_size = 0;
177 : :
178 : 5 : if (spdm_response_size <=
179 : 5 : (sizeof(spdm_challenge_auth_response_t) + hash_size + SPDM_NONCE_SIZE +
180 [ - + ]: 5 : measurement_summary_hash_size + sizeof(uint16_t))) {
181 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
182 : : }
183 : :
184 : 5 : ptr = (const void *)(spdm_response + 1);
185 : :
186 : 5 : cert_chain_hash = ptr;
187 : 5 : ptr += hash_size;
188 : 5 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap cert_chain_hash (0x%zx) - ", hash_size));
189 : 5 : LIBSPDM_INTERNAL_DUMP_DATA(cert_chain_hash, hash_size);
190 : 5 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
191 [ + + ]: 5 : if (encap_context->req_slot_id == 0xFF) {
192 : 1 : result = libspdm_verify_public_key_hash(spdm_context, cert_chain_hash, hash_size);
193 : : } else {
194 : 4 : result = libspdm_verify_certificate_chain_hash(
195 : 4 : spdm_context, encap_context->req_slot_id,
196 : : cert_chain_hash, hash_size);
197 : : }
198 [ - + ]: 5 : if (!result) {
199 : 0 : return LIBSPDM_STATUS_INVALID_CERT;
200 : : }
201 : :
202 : 5 : LIBSPDM_DEBUG_CODE(
203 : : const void *nonce;
204 : : nonce = ptr;
205 : : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap nonce (0x%x) - ", SPDM_NONCE_SIZE));
206 : : LIBSPDM_INTERNAL_DUMP_DATA(nonce, SPDM_NONCE_SIZE);
207 : : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
208 : : );
209 : 5 : ptr += SPDM_NONCE_SIZE;
210 : :
211 : 5 : LIBSPDM_DEBUG_CODE(
212 : : const void *measurement_summary_hash;
213 : : measurement_summary_hash = ptr;
214 : : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap measurement_summary_hash (0x%x) - ",
215 : : measurement_summary_hash_size));
216 : : LIBSPDM_INTERNAL_DUMP_DATA(measurement_summary_hash, measurement_summary_hash_size);
217 : : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
218 : : );
219 : 5 : ptr += measurement_summary_hash_size;
220 : :
221 : 5 : opaque_length = libspdm_read_uint16(ptr);
222 [ + + ]: 5 : if (opaque_length > SPDM_MAX_OPAQUE_DATA_SIZE) {
223 : 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
224 : : }
225 : 4 : ptr += sizeof(uint16_t);
226 : :
227 [ + + ]: 4 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
228 : 1 : if (spdm_response_size <
229 : : sizeof(spdm_challenge_auth_response_t) + hash_size +
230 : 1 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
231 [ - + ]: 1 : sizeof(uint16_t) + opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size) {
232 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
233 : : }
234 : 1 : spdm_response_size = sizeof(spdm_challenge_auth_response_t) +
235 : 1 : hash_size + SPDM_NONCE_SIZE +
236 : 1 : measurement_summary_hash_size + sizeof(uint16_t) +
237 : 1 : opaque_length + SPDM_REQ_CONTEXT_SIZE + signature_size;
238 : : } else {
239 : 3 : if (spdm_response_size <
240 : : sizeof(spdm_challenge_auth_response_t) + hash_size +
241 : 3 : SPDM_NONCE_SIZE + measurement_summary_hash_size +
242 [ - + ]: 3 : sizeof(uint16_t) + opaque_length + signature_size) {
243 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
244 : : }
245 : 3 : spdm_response_size = sizeof(spdm_challenge_auth_response_t) +
246 : 3 : hash_size + SPDM_NONCE_SIZE +
247 : 3 : measurement_summary_hash_size + sizeof(uint16_t) +
248 : 3 : opaque_length + signature_size;
249 : : }
250 : :
251 : 4 : LIBSPDM_DEBUG_CODE(
252 : : const void *opaque;
253 : : opaque = ptr;
254 : : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap opaque (0x%x):\n", opaque_length));
255 : : LIBSPDM_INTERNAL_DUMP_HEX(opaque, opaque_length);
256 : : );
257 : 4 : ptr += opaque_length;
258 : :
259 [ + + ]: 4 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
260 [ - + ]: 1 : if (!libspdm_consttime_is_mem_equal(encap_context->req_context, ptr,
261 : : SPDM_REQ_CONTEXT_SIZE)) {
262 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
263 : : }
264 : 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap RequesterContext - "));
265 : 1 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_REQ_CONTEXT_SIZE);
266 : 1 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
267 : 1 : ptr += SPDM_REQ_CONTEXT_SIZE;
268 : : }
269 : :
270 : 4 : status = libspdm_append_message_mut_c(spdm_context, spdm_response,
271 : : spdm_response_size - signature_size);
272 [ - + ]: 4 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
273 : 0 : return LIBSPDM_STATUS_BUFFER_FULL;
274 : : }
275 : :
276 : 4 : signature = ptr;
277 : 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap signature (0x%zx):\n", signature_size));
278 : 4 : LIBSPDM_INTERNAL_DUMP_HEX(signature, signature_size);
279 : 4 : result = libspdm_verify_challenge_auth_signature(
280 : 4 : spdm_context, false, encap_context->req_slot_id, signature, signature_size);
281 [ - + ]: 4 : if (!result) {
282 : 0 : return LIBSPDM_STATUS_VERIF_FAIL;
283 : : }
284 : :
285 : 4 : libspdm_set_connection_state(spdm_context, LIBSPDM_CONNECTION_STATE_AUTHENTICATED);
286 : :
287 : 4 : *need_continue = false;
288 : :
289 : 4 : return LIBSPDM_STATUS_SUCCESS;
290 : : }
291 : :
292 : : #endif /* (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (..) */
|