Branch data Line data Source code
1 : : /**
2 : : * Copyright Notice:
3 : : * Copyright 2023-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_requester_lib.h"
8 : :
9 : : #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
10 : :
11 : : #define SPDM_MAX_VENDOR_PAYLOAD_LEN (SPDM_MAX_VENDOR_ID_LENGTH + 2 + 4 + \
12 : : SPDM_MAX_VENDOR_DEFINED_DATA_LEN_14)
13 : :
14 : : #pragma pack(1)
15 : : typedef struct {
16 : : spdm_message_header_t header;
17 : : uint16_t standard_id;
18 : : uint8_t vendor_id_len;
19 : : uint8_t vendor_plus_request[SPDM_MAX_VENDOR_PAYLOAD_LEN];
20 : : } libspdm_vendor_defined_response_msg_max_t;
21 : : #pragma pack()
22 : :
23 : 11 : static libspdm_return_t libspdm_try_vendor_send_request_receive_response(
24 : : libspdm_context_t *spdm_context,
25 : : const uint32_t *session_id,
26 : : uint16_t req_standard_id,
27 : : uint8_t req_vendor_id_len,
28 : : const void *req_vendor_id,
29 : : uint32_t req_size,
30 : : const void *req_data,
31 : : uint16_t *resp_standard_id,
32 : : uint8_t *resp_vendor_id_len,
33 : : void *resp_vendor_id,
34 : : uint32_t *resp_size,
35 : : void *resp_data)
36 : : {
37 : : libspdm_return_t status;
38 : : spdm_vendor_defined_request_msg_t *spdm_request;
39 : : size_t spdm_request_size;
40 : : libspdm_vendor_defined_response_msg_max_t *spdm_response;
41 : : size_t spdm_response_size;
42 : : uint8_t *message;
43 : 11 : size_t message_size = 0;
44 : : size_t transport_header_size;
45 : 11 : size_t max_payload = 0;
46 : 11 : uint8_t* vendor_request = NULL;
47 : 11 : uint8_t *response_ptr = NULL;
48 : 11 : uint32_t response_size = 0;
49 : : bool use_large_payload;
50 : :
51 : : /* -=[Check Parameters Phase]=- */
52 [ + - ]: 11 : if (spdm_context == NULL ||
53 [ + - + - : 11 : (req_size != 0 && req_data == NULL) ||
+ - ]
54 [ + - ]: 11 : resp_standard_id == NULL ||
55 [ + - ]: 11 : resp_vendor_id_len == NULL ||
56 [ + - ]: 11 : resp_vendor_id == NULL ||
57 : 11 : resp_size == NULL ||
58 [ + + - + ]: 11 : (*resp_size != 0 && resp_data == NULL)
59 : : ) {
60 : 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
61 : : }
62 : :
63 [ - + ]: 11 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
64 : 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
65 : : }
66 : :
67 : 11 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
68 : :
69 [ - + ]: 11 : if (req_size > SPDM_MAX_VENDOR_DEFINED_DATA_LEN) {
70 [ # # ]: 0 : if (libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_14) {
71 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
72 [ # # ]: 0 : } else if (!libspdm_is_capabilities_flag_supported(
73 : : spdm_context, true,
74 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP,
75 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
76 : 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
77 : : }
78 : : }
79 : :
80 [ + + + - ]: 15 : if ((libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14) &&
81 : 4 : libspdm_is_capabilities_flag_supported(
82 : : spdm_context, true,
83 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP,
84 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
85 : 4 : use_large_payload = true;
86 : : } else {
87 : 7 : use_large_payload = false;
88 : : }
89 : :
90 : : /* -=[Construct Request Phase]=- */
91 : 11 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
92 [ - + ]: 11 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
93 : 0 : return status;
94 : : }
95 : :
96 : : /* calculate useful payload the sender buffer can hold after
97 : : * removing all protocol, spdm and vendor defined message headers
98 : : * -3 bytes is for the standard_id and vendor_id_len fields in the vendor header
99 : : * -2 bytes is for the payload length field */
100 : 11 : max_payload = message_size - transport_header_size -
101 : 11 : spdm_context->local_context.capability.transport_tail_size
102 : 11 : - sizeof(spdm_request->header) - 3 - req_vendor_id_len - 2;
103 : :
104 [ - + ]: 11 : LIBSPDM_ASSERT (message_size >= transport_header_size +
105 : : spdm_context->local_context.capability.transport_tail_size);
106 : :
107 : : /* do not accept requests exceeding maximum allowed payload */
108 [ - + ]: 11 : if ((size_t)req_size > max_payload) {
109 : 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
110 : : }
111 : :
112 : 11 : spdm_request = (void *)(message + transport_header_size);
113 : 11 : spdm_request_size = message_size - transport_header_size -
114 : 11 : spdm_context->local_context.capability.transport_tail_size;
115 : :
116 [ - + ]: 11 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_vendor_defined_request_msg_t) +
117 : : req_vendor_id_len + sizeof(uint16_t) + req_size);
118 : 11 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
119 : 11 : spdm_request->header.request_response_code = SPDM_VENDOR_DEFINED_REQUEST;
120 : 11 : spdm_request->header.param1 = 0;
121 : 11 : spdm_request->header.param2 = 0;
122 : : /* Message header here */
123 : 11 : spdm_request->standard_id = req_standard_id;
124 : 11 : spdm_request->len = req_vendor_id_len;
125 : :
126 : : /* Copy Vendor id */
127 : 11 : vendor_request = ((uint8_t *)spdm_request) + sizeof(spdm_vendor_defined_request_msg_t);
128 [ + - ]: 11 : if (req_vendor_id_len != 0) {
129 : 11 : libspdm_copy_mem(vendor_request, req_vendor_id_len, req_vendor_id, req_vendor_id_len);
130 : 11 : vendor_request += req_vendor_id_len;
131 : : }
132 : :
133 [ + + ]: 11 : if (use_large_payload) {
134 : 4 : spdm_request->header.param1 |= SPDM_VENDOR_DEFINED_REQUEST_LARGE_REQ;
135 : : /* skip request_len */
136 : 4 : vendor_request += sizeof(uint16_t);
137 : :
138 : : /* Copy large_request_len */
139 : 4 : libspdm_copy_mem(vendor_request, sizeof(uint32_t), &req_size, sizeof(uint32_t));
140 : 4 : vendor_request += sizeof(uint32_t);
141 : :
142 : : /* Copy payload */
143 [ + - ]: 4 : if (req_size != 0) {
144 : 4 : libspdm_copy_mem(vendor_request, req_size, req_data, req_size);
145 : : }
146 : :
147 : 4 : spdm_request_size = sizeof(spdm_vendor_defined_request_msg_t) +
148 : 4 : req_vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t) + req_size;
149 : :
150 : : } else {
151 : : /* Copy request_len */
152 : 7 : libspdm_copy_mem(vendor_request, sizeof(uint16_t), &req_size, sizeof(uint16_t));
153 : 7 : vendor_request += sizeof(uint16_t);
154 : :
155 : : /* Copy payload */
156 [ + - ]: 7 : if (req_size != 0) {
157 : 7 : libspdm_copy_mem(vendor_request, req_size, req_data, req_size);
158 : : }
159 : :
160 : 7 : spdm_request_size = sizeof(spdm_vendor_defined_request_msg_t) +
161 : 7 : req_vendor_id_len + sizeof(uint16_t) + req_size;
162 : : }
163 : :
164 : : /* -=[Send Request Phase]=- */
165 : 11 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
166 [ + + ]: 11 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
167 : 1 : libspdm_release_sender_buffer (spdm_context);
168 : 1 : return LIBSPDM_STATUS_SEND_FAIL;
169 : : }
170 : 10 : libspdm_zero_mem(message, message_size);
171 : 10 : libspdm_release_sender_buffer (spdm_context);
172 : 10 : spdm_request = (void *)spdm_context->last_spdm_request;
173 : :
174 : : /* -=[Receive Response Phase]=- */
175 : 10 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
176 [ - + ]: 10 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
177 : 0 : return status;
178 : : }
179 [ - + ]: 10 : LIBSPDM_ASSERT (message_size >= transport_header_size);
180 : 10 : spdm_response = (void *)(message);
181 : 10 : spdm_response_size = message_size;
182 : :
183 : 10 : status = libspdm_receive_spdm_response(spdm_context, session_id,
184 : : &spdm_response_size,
185 : : (void **)&spdm_response);
186 : :
187 [ + + ]: 10 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
188 : 2 : status = LIBSPDM_STATUS_RECEIVE_FAIL;
189 : 2 : goto done;
190 : : }
191 : :
192 : : /* -=[Validate Response Phase]=- */
193 [ - + ]: 8 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
194 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
195 : 0 : goto done;
196 : : }
197 [ + + ]: 8 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
198 : 1 : status = libspdm_handle_error_response_main(
199 : : spdm_context, session_id,
200 : : &spdm_response_size,
201 : : (void **)&spdm_response, SPDM_VENDOR_DEFINED_REQUEST,
202 : : SPDM_VENDOR_DEFINED_RESPONSE);
203 [ + - ]: 1 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
204 : 1 : goto done;
205 : : }
206 [ - + ]: 7 : } else if (spdm_response->header.request_response_code != SPDM_VENDOR_DEFINED_RESPONSE) {
207 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
208 : 0 : goto done;
209 : : }
210 [ - + ]: 7 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
211 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
212 : 0 : goto done;
213 : : }
214 : :
215 [ - + ]: 7 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t)) {
216 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
217 : 0 : goto done;
218 : : }
219 : :
220 [ - + ]: 7 : if (!libspdm_validate_svh_vendor_id_len(spdm_response->standard_id,
221 : 7 : spdm_response->vendor_id_len)) {
222 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
223 : 0 : goto done;
224 : : }
225 : :
226 : 7 : if ((spdm_response->header.param1 & SPDM_VENDOR_DEFINED_RESPONSE_LARGE_RESP) !=
227 [ + + ]: 7 : (spdm_request->header.param1 & SPDM_VENDOR_DEFINED_REQUEST_LARGE_REQ)) {
228 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
229 : 1 : goto done;
230 : : }
231 : :
232 [ + + ]: 6 : if (use_large_payload) {
233 : : /* check response buffer size at least spdm response default header plus
234 : : * number of bytes required by vendor id and 2 bytes for reserved and 4 bytes
235 : : * for large response payload size */
236 : 3 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t) +
237 [ + + ]: 3 : spdm_response->vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t)) {
238 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
239 : 1 : goto done;
240 : : }
241 : : } else {
242 : : /* check response buffer size at least spdm response default header plus
243 : : * number of bytes required by vendor id and 2 bytes for response payload size */
244 : 3 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t) +
245 [ - + ]: 3 : spdm_response->vendor_id_len + sizeof(uint16_t)) {
246 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
247 : 0 : goto done;
248 : : }
249 : : }
250 : :
251 : 5 : *resp_standard_id = spdm_response->standard_id;
252 [ - + ]: 5 : if (*resp_vendor_id_len < spdm_response->vendor_id_len) {
253 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
254 : 0 : goto done;
255 : : }
256 : 5 : *resp_vendor_id_len = spdm_response->vendor_id_len;
257 [ + - ]: 5 : if ((*resp_vendor_id_len) != 0) {
258 : 5 : libspdm_copy_mem(resp_vendor_id, *resp_vendor_id_len, spdm_response->vendor_plus_request,
259 : 5 : *resp_vendor_id_len);
260 : : }
261 : :
262 : : /* -=[Process Response Phase]=- */
263 : 5 : response_ptr = spdm_response->vendor_plus_request + spdm_response->vendor_id_len;
264 [ + + ]: 5 : if (use_large_payload) {
265 : 2 : response_ptr += sizeof(uint16_t);
266 : 2 : response_size = libspdm_read_uint32(response_ptr);
267 : 2 : if (spdm_response_size < response_size +
268 : 2 : sizeof(spdm_vendor_defined_response_msg_t) +
269 [ + + ]: 2 : spdm_response->vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t)) {
270 : 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
271 : 1 : goto done;
272 : : }
273 : 1 : response_ptr += sizeof(uint32_t);
274 : : } else {
275 : 3 : response_size = libspdm_read_uint16(response_ptr);
276 : :
277 : 3 : if (spdm_response_size < response_size +
278 : 3 : sizeof(spdm_vendor_defined_response_msg_t) +
279 [ - + ]: 3 : spdm_response->vendor_id_len + sizeof(uint16_t)) {
280 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
281 : 0 : goto done;
282 : : }
283 : 3 : response_ptr += sizeof(uint16_t);
284 : : }
285 : :
286 [ + + ]: 4 : if (*resp_size < response_size) {
287 : 2 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
288 : 2 : goto done;
289 : : }
290 : 2 : libspdm_copy_mem(resp_data, *resp_size, response_ptr, response_size);
291 : 2 : *resp_size = response_size;
292 : :
293 : : /* -=[Log Message Phase]=- */
294 : : #if LIBSPDM_ENABLE_MSG_LOG
295 : 2 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
296 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
297 : :
298 : 2 : status = LIBSPDM_STATUS_SUCCESS;
299 : 10 : done:
300 : 10 : libspdm_zero_mem(spdm_context->last_spdm_request,
301 : 10 : libspdm_get_scratch_buffer_last_spdm_request_capacity(spdm_context));
302 : 10 : spdm_context->last_spdm_request_size = 0;
303 : : /*
304 : : * receiver buffer "message" contains encrypted message
305 : : * "spdm_response" contains the plain-text VDM message
306 : : */
307 : 10 : libspdm_zero_mem(spdm_response, spdm_response_size);
308 : 10 : libspdm_release_receiver_buffer (spdm_context); /* this will free up response-message, need to find workaround */
309 : 10 : return status;
310 : : }
311 : :
312 : 11 : libspdm_return_t libspdm_vendor_send_request_receive_response(
313 : : void *spdm_context,
314 : : const uint32_t *session_id,
315 : : uint16_t req_standard_id,
316 : : uint8_t req_vendor_id_len,
317 : : const void *req_vendor_id,
318 : : uint32_t req_size,
319 : : const void *req_data,
320 : : uint16_t *resp_standard_id,
321 : : uint8_t *resp_vendor_id_len,
322 : : void *resp_vendor_id,
323 : : uint32_t *resp_size,
324 : : void *resp_data)
325 : : {
326 : : libspdm_context_t *context;
327 : : size_t retry;
328 : : uint64_t retry_delay_time;
329 : : libspdm_return_t status;
330 : :
331 : 11 : context = spdm_context;
332 : 11 : context->crypto_request = true;
333 : 11 : retry = context->retry_times;
334 : 11 : retry_delay_time = context->retry_delay_time;
335 : : do {
336 : 11 : status = libspdm_try_vendor_send_request_receive_response(
337 : : context,
338 : : session_id,
339 : : req_standard_id,
340 : : req_vendor_id_len,
341 : : req_vendor_id,
342 : : req_size,
343 : : req_data,
344 : : resp_standard_id,
345 : : resp_vendor_id_len,
346 : : resp_vendor_id,
347 : : resp_size,
348 : : resp_data);
349 [ + - ]: 11 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
350 : 11 : return status;
351 : : }
352 : :
353 : 0 : libspdm_sleep(retry_delay_time);
354 [ # # ]: 0 : } while (retry-- != 0);
355 : :
356 : 0 : return status;
357 : : }
358 : :
359 : : #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
|