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