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