Branch data Line data Source code
1 : : /**
2 : : * Copyright Notice:
3 : : * Copyright 2025-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_ENCAP_CAP) && (LIBSPDM_SEND_GET_ENDPOINT_INFO_SUPPORT)
10 : :
11 : 28 : libspdm_return_t libspdm_get_encap_request_get_endpoint_info(
12 : : void *context,
13 : : const uint32_t *session_id,
14 : : uint8_t sub_code,
15 : : uint8_t slot_id,
16 : : uint8_t request_attributes,
17 : : size_t ep_info_size,
18 : : void *ep_info,
19 : : size_t *encap_request_size,
20 : : void *encap_request)
21 : : {
22 : : libspdm_encap_context_t *encap_context;
23 : : libspdm_context_t *spdm_context;
24 : : libspdm_return_t status;
25 : : spdm_get_endpoint_info_request_t *spdm_request;
26 : : libspdm_session_info_t *session_info;
27 : : libspdm_session_state_t session_state;
28 : : uint8_t *spdm_nonce;
29 : :
30 : 28 : spdm_context = context;
31 : :
32 [ + + + + ]: 28 : if ((ep_info == NULL) || (ep_info_size == 0)) {
33 : 4 : return LIBSPDM_STATUS_INVALID_PARAMETER;
34 : : }
35 : :
36 [ + + + + ]: 24 : if ((slot_id >= SPDM_MAX_SLOT_COUNT) && (slot_id != 0xF)) {
37 : : /* SlotID is a four-bit field in which 0xF designates the Requester's provisioned public
38 : : * key. Any other slot indexes per-slot state of SPDM_MAX_SLOT_COUNT entries, which
39 : : * ENDPOINT_INFO is verified against. */
40 : 6 : return LIBSPDM_STATUS_INVALID_PARAMETER;
41 : : }
42 : :
43 : 18 : encap_context = libspdm_get_encap_context(spdm_context, session_id);
44 [ - + ]: 18 : if (encap_context == NULL) {
45 : : /* session_id does not refer to an existing session. */
46 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
47 : : }
48 : :
49 : 18 : encap_context->has_last_encap_request = false;
50 : :
51 : : /* The endpoint information is written here once the ENDPOINT_INFO response is verified. */
52 : 18 : encap_context->payload_buffer = ep_info;
53 : 18 : encap_context->payload_buffer_max_size = ep_info_size;
54 : 18 : encap_context->payload_buffer_size = 0;
55 : :
56 [ + + ]: 18 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_13) {
57 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
58 : : }
59 : :
60 [ + + ]: 16 : if (!libspdm_is_capabilities_flag_supported(
61 : : spdm_context, false,
62 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_EP_INFO_CAP, 0)) {
63 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
64 : : }
65 : :
66 [ + + ]: 14 : if (((request_attributes &
67 : 10 : SPDM_GET_ENDPOINT_INFO_REQUEST_ATTRIBUTE_SIGNATURE_REQUESTED) != 0) &&
68 [ + + ]: 10 : !libspdm_is_capabilities_flag_supported(
69 : : spdm_context, false,
70 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_EP_INFO_CAP_SIG, 0)) {
71 : : /* The Requester cannot sign ENDPOINT_INFO, and would reject the request with
72 : : * ERROR(UnsupportedRequest), so do not send it. */
73 : 2 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
74 : : }
75 : :
76 [ + + ]: 12 : if (session_id != NULL) {
77 : 4 : session_info = libspdm_get_session_info_via_session_id(spdm_context, *session_id);
78 [ - + ]: 4 : if (session_info == NULL) {
79 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
80 : : }
81 : 4 : session_state = libspdm_secured_message_get_session_state(
82 : : session_info->secured_message_context);
83 [ + + ]: 4 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
84 : 2 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
85 : : }
86 : : } else {
87 : 8 : session_info = NULL;
88 : : }
89 : :
90 : 10 : LIBSPDM_ASSERT(*encap_request_size >= sizeof(spdm_get_endpoint_info_request_t));
91 : :
92 : : /* Store slot_id in context so process_encap_response can retrieve it. */
93 : 10 : encap_context->req_slot_id = slot_id;
94 : :
95 : 10 : spdm_request = encap_request;
96 : :
97 : 10 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
98 : 10 : spdm_request->header.request_response_code = SPDM_GET_ENDPOINT_INFO;
99 : 10 : spdm_request->header.param1 = sub_code;
100 : 10 : spdm_request->header.param2 = slot_id & SPDM_GET_ENDPOINT_INFO_REQUEST_SLOT_ID_MASK;
101 : :
102 [ + + ]: 10 : if (request_attributes & SPDM_GET_ENDPOINT_INFO_REQUEST_ATTRIBUTE_SIGNATURE_REQUESTED) {
103 : 6 : LIBSPDM_ASSERT(
104 : : *encap_request_size >= sizeof(spdm_get_endpoint_info_request_t) + SPDM_NONCE_SIZE);
105 : 6 : *encap_request_size = sizeof(spdm_get_endpoint_info_request_t) + SPDM_NONCE_SIZE;
106 : :
107 : 6 : spdm_request->request_attributes =
108 : : SPDM_GET_ENDPOINT_INFO_REQUEST_ATTRIBUTE_SIGNATURE_REQUESTED;
109 : 6 : libspdm_write_uint24(spdm_request->reserved, 0);
110 : :
111 : 6 : spdm_nonce = (uint8_t *)(spdm_request + 1);
112 [ - + ]: 6 : if (!libspdm_get_random_number(SPDM_NONCE_SIZE, spdm_nonce)) {
113 : 0 : return LIBSPDM_STATUS_LOW_ENTROPY;
114 : : }
115 : 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap RequesterNonce - "));
116 : 6 : LIBSPDM_INTERNAL_DUMP_DATA(spdm_nonce, SPDM_NONCE_SIZE);
117 : 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
118 : :
119 : 6 : libspdm_reset_message_encap_e(spdm_context, session_info);
120 : :
121 : 6 : status = libspdm_append_message_encap_e(spdm_context, session_info,
122 : : spdm_request, *encap_request_size);
123 [ - + ]: 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
124 : 0 : return status;
125 : : }
126 : :
127 : : } else {
128 : 4 : *encap_request_size = sizeof(spdm_get_endpoint_info_request_t);
129 : 4 : spdm_request->request_attributes = 0;
130 : 4 : libspdm_write_uint24(spdm_request->reserved, 0);
131 : : }
132 : :
133 : : /* Store the RequestAttributes that were sent, as last_encap_request_header only retains the
134 : : * message header and process_encap_response must honour what was requested. */
135 : 10 : encap_context->req_attributes = spdm_request->request_attributes;
136 : :
137 : 10 : libspdm_copy_mem(&encap_context->last_encap_request_header,
138 : : sizeof(encap_context->last_encap_request_header),
139 : 10 : &spdm_request->header, sizeof(spdm_message_header_t));
140 : 10 : encap_context->has_last_encap_request = true;
141 : :
142 : 10 : return LIBSPDM_STATUS_SUCCESS;
143 : : }
144 : :
145 : 40 : libspdm_return_t libspdm_process_encap_response_endpoint_info(
146 : : libspdm_context_t *spdm_context, size_t encap_response_size,
147 : : const void *encap_response, bool *need_continue)
148 : : {
149 : : libspdm_encap_context_t *encap_context;
150 : : libspdm_return_t status;
151 : : const spdm_endpoint_info_response_t *spdm_response;
152 : : size_t spdm_response_size;
153 : : uint32_t session_id;
154 : : libspdm_session_info_t *session_info;
155 : : libspdm_session_state_t session_state;
156 : : const uint8_t *ptr;
157 : : const uint8_t *ep_info_data;
158 : : uint32_t ep_info_data_len;
159 : : size_t signature_size;
160 : : const void *signature;
161 : : uint8_t slot_id;
162 : : bool result;
163 : : uint8_t request_attributes;
164 : :
165 [ - + ]: 40 : if (spdm_context->last_spdm_request_session_id_valid) {
166 : 0 : session_id = spdm_context->last_spdm_request_session_id;
167 : 0 : session_info = libspdm_get_session_info_via_session_id(spdm_context, session_id);
168 [ # # ]: 0 : if (session_info == NULL) {
169 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
170 : : }
171 : 0 : session_state = libspdm_secured_message_get_session_state(
172 : : session_info->secured_message_context);
173 [ # # ]: 0 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
174 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
175 : : }
176 : : } else {
177 : 40 : session_info = NULL;
178 : : }
179 : :
180 : 40 : encap_context = libspdm_get_encap_context_via_last_request(spdm_context);
181 : :
182 : 40 : spdm_response = encap_response;
183 : 40 : spdm_response_size = encap_response_size;
184 : :
185 [ + + ]: 40 : if (spdm_response->header.spdm_version != libspdm_get_connection_version (spdm_context)) {
186 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
187 : : }
188 : :
189 [ + + ]: 38 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
190 : 6 : status = libspdm_handle_encap_error_response_main(spdm_response->header.param1);
191 [ + - ]: 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
192 : 6 : return status;
193 : : }
194 [ + + ]: 32 : } else if (spdm_response->header.request_response_code != SPDM_ENDPOINT_INFO) {
195 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
196 : : }
197 : :
198 [ - + ]: 30 : if (spdm_response_size < sizeof(spdm_endpoint_info_response_t) + sizeof(uint32_t)) {
199 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
200 : : }
201 : :
202 : 30 : slot_id = encap_context->req_slot_id & SPDM_GET_ENDPOINT_INFO_REQUEST_SLOT_ID_MASK;
203 : :
204 : : /* The Integrator decides whether a signature is requested, so the response is processed
205 : : * according to the RequestAttributes that were sent. */
206 : 30 : request_attributes = encap_context->req_attributes;
207 : :
208 [ + + ]: 30 : if ((request_attributes & SPDM_GET_ENDPOINT_INFO_REQUEST_ATTRIBUTE_SIGNATURE_REQUESTED) != 0) {
209 [ - + ]: 16 : if (spdm_context->connection_info.algorithm.req_pqc_asym_alg != 0) {
210 : 0 : signature_size = libspdm_get_req_pqc_asym_signature_size(
211 : : spdm_context->connection_info.algorithm.req_pqc_asym_alg);
212 : : } else {
213 : 16 : signature_size = libspdm_get_req_asym_signature_size(
214 : 16 : spdm_context->connection_info.algorithm.req_base_asym_alg);
215 : : }
216 [ + + ]: 16 : if ((spdm_response->header.param2 & SPDM_ENDPOINT_INFO_RESPONSE_SLOT_ID_MASK) != slot_id) {
217 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
218 : : }
219 : :
220 : 14 : if (spdm_response_size <
221 [ + + ]: 14 : sizeof(spdm_endpoint_info_response_t) + SPDM_NONCE_SIZE + signature_size) {
222 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
223 : : }
224 : :
225 : 12 : ptr = (const uint8_t *)(spdm_response + 1);
226 : 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Encap ResponderNonce (0x%x) - ", SPDM_NONCE_SIZE));
227 : 12 : LIBSPDM_INTERNAL_DUMP_DATA(ptr, SPDM_NONCE_SIZE);
228 : 12 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "\n"));
229 : :
230 : 12 : ptr += SPDM_NONCE_SIZE;
231 : 12 : ep_info_data_len = libspdm_read_uint32(ptr);
232 : :
233 : 12 : if (spdm_response_size !=
234 : : sizeof(spdm_endpoint_info_response_t) + SPDM_NONCE_SIZE +
235 [ + + ]: 12 : signature_size + ep_info_data_len + sizeof(uint32_t)) {
236 : 2 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
237 : : }
238 : 10 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ep_info_data_len - 0x%06x\n",
239 : : ep_info_data_len));
240 : 10 : ptr += sizeof(uint32_t);
241 : 10 : ep_info_data = ptr;
242 : :
243 : 10 : status = libspdm_append_message_encap_e(spdm_context, session_info, spdm_response,
244 : : spdm_response_size - signature_size);
245 [ - + ]: 10 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
246 : 0 : return status;
247 : : }
248 : :
249 : 10 : ptr += ep_info_data_len;
250 : 10 : signature = ptr;
251 : 10 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "signature (0x%zx):\n", signature_size));
252 : 10 : LIBSPDM_INTERNAL_DUMP_HEX(signature, signature_size);
253 : :
254 : 10 : result = libspdm_verify_endpoint_info_signature(
255 : : spdm_context, session_info, false, slot_id, signature, signature_size);
256 [ + + ]: 10 : if (!result) {
257 : 2 : return LIBSPDM_STATUS_VERIF_FAIL;
258 : : }
259 : :
260 : 8 : libspdm_reset_message_encap_e(spdm_context, session_info);
261 : : } else {
262 : : /* responder's slot_id should be 0 */
263 [ + + ]: 14 : if ((spdm_response->header.param2 & SPDM_ENDPOINT_INFO_RESPONSE_SLOT_ID_MASK) != 0) {
264 : 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
265 : : }
266 : :
267 : : /* nonce and signature not present */
268 : 12 : ptr = (const uint8_t *)(spdm_response + 1);
269 : 12 : ep_info_data_len = libspdm_read_uint32(ptr);
270 : 12 : if (spdm_response_size <
271 [ + + ]: 12 : sizeof(spdm_endpoint_info_response_t) + ep_info_data_len + sizeof(uint32_t)) {
272 : 4 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
273 : : }
274 : :
275 : 8 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "ep_info_data_len - 0x%06x\n",
276 : : ep_info_data_len));
277 : 8 : ptr += sizeof(uint32_t);
278 : 8 : ep_info_data = ptr;
279 : : }
280 : :
281 : 16 : *need_continue = false;
282 : :
283 [ + + ]: 16 : if (ep_info_data_len > encap_context->payload_buffer_max_size) {
284 : 4 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "endpoint info buffer too small\n"));
285 : 4 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
286 : : }
287 : :
288 [ + - ]: 12 : if (ep_info_data_len != 0) {
289 : 12 : libspdm_copy_mem(encap_context->payload_buffer,
290 : : encap_context->payload_buffer_max_size,
291 : : ep_info_data, ep_info_data_len);
292 : : }
293 : 12 : encap_context->payload_buffer_size = ep_info_data_len;
294 : :
295 : 12 : return LIBSPDM_STATUS_SUCCESS;
296 : : }
297 : :
298 : : #endif /* (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (...) */
|