Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2023-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_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 10 : 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 10 : size_t message_size = 0;
44 : size_t transport_header_size;
45 10 : size_t max_payload = 0;
46 10 : uint8_t* vendor_request = NULL;
47 10 : uint8_t *response_ptr = NULL;
48 10 : uint32_t response_size = 0;
49 : bool use_large_payload;
50 :
51 : /* -=[Check Parameters Phase]=- */
52 10 : if (spdm_context == NULL ||
53 10 : (req_size != 0 && req_data == NULL) ||
54 10 : resp_standard_id == NULL ||
55 10 : resp_vendor_id_len == NULL ||
56 10 : resp_vendor_id == NULL ||
57 10 : resp_size == NULL ||
58 10 : (*resp_size != 0 && resp_data == NULL)
59 : ) {
60 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
61 : }
62 :
63 10 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
64 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
65 : }
66 :
67 10 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
68 :
69 10 : 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 14 : 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 6 : use_large_payload = false;
88 : }
89 :
90 : /* -=[Construct Request Phase]=- */
91 10 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
92 10 : 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 10 : max_payload = message_size - transport_header_size -
101 10 : spdm_context->local_context.capability.transport_tail_size
102 10 : - sizeof(spdm_request->header) - 3 - req_vendor_id_len - 2;
103 :
104 10 : 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 10 : if ((size_t)req_size > max_payload) {
109 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
110 : }
111 :
112 10 : spdm_request = (void *)(message + transport_header_size);
113 10 : spdm_request_size = message_size - transport_header_size -
114 10 : spdm_context->local_context.capability.transport_tail_size;
115 :
116 10 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_vendor_defined_request_msg_t) +
117 : req_vendor_id_len + sizeof(uint16_t) + req_size);
118 10 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
119 10 : spdm_request->header.request_response_code = SPDM_VENDOR_DEFINED_REQUEST;
120 10 : spdm_request->header.param1 = 0;
121 10 : spdm_request->header.param2 = 0;
122 : /* Message header here */
123 10 : spdm_request->standard_id = req_standard_id;
124 10 : spdm_request->len = req_vendor_id_len;
125 :
126 : /* Copy Vendor id */
127 10 : vendor_request = ((uint8_t *)spdm_request) + sizeof(spdm_vendor_defined_request_msg_t);
128 10 : if (req_vendor_id_len != 0) {
129 10 : libspdm_copy_mem(vendor_request, req_vendor_id_len, req_vendor_id, req_vendor_id_len);
130 10 : vendor_request += req_vendor_id_len;
131 : }
132 :
133 10 : 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 6 : libspdm_copy_mem(vendor_request, sizeof(uint16_t), &req_size, sizeof(uint16_t));
153 6 : vendor_request += sizeof(uint16_t);
154 :
155 : /* Copy payload */
156 6 : if (req_size != 0) {
157 6 : libspdm_copy_mem(vendor_request, req_size, req_data, req_size);
158 : }
159 :
160 6 : spdm_request_size = sizeof(spdm_vendor_defined_request_msg_t) +
161 6 : req_vendor_id_len + sizeof(uint16_t) + req_size;
162 : }
163 :
164 : /* -=[Send Request Phase]=- */
165 10 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
166 10 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
167 1 : libspdm_release_sender_buffer (spdm_context);
168 1 : return LIBSPDM_STATUS_SEND_FAIL;
169 : }
170 9 : libspdm_release_sender_buffer (spdm_context);
171 9 : spdm_request = (void *)spdm_context->last_spdm_request;
172 :
173 : /* -=[Receive Response Phase]=- */
174 9 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
175 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
176 0 : return status;
177 : }
178 9 : LIBSPDM_ASSERT (message_size >= transport_header_size);
179 9 : spdm_response = (void *)(message);
180 9 : spdm_response_size = message_size;
181 :
182 9 : status = libspdm_receive_spdm_response(spdm_context, session_id,
183 : &spdm_response_size,
184 : (void **)&spdm_response);
185 :
186 9 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
187 2 : status = LIBSPDM_STATUS_RECEIVE_FAIL;
188 2 : goto done;
189 : }
190 :
191 : /* -=[Validate Response Phase]=- */
192 7 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
193 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
194 0 : goto done;
195 : }
196 7 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
197 1 : status = libspdm_handle_error_response_main(
198 : spdm_context, session_id,
199 : &spdm_response_size,
200 : (void **)&spdm_response, SPDM_VENDOR_DEFINED_REQUEST,
201 : SPDM_VENDOR_DEFINED_RESPONSE);
202 1 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
203 1 : goto done;
204 : }
205 6 : } else if (spdm_response->header.request_response_code != SPDM_VENDOR_DEFINED_RESPONSE) {
206 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
207 0 : goto done;
208 : }
209 6 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
210 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
211 0 : goto done;
212 : }
213 :
214 6 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t)) {
215 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
216 0 : goto done;
217 : }
218 :
219 6 : if (!libspdm_validate_svh_vendor_id_len(spdm_response->standard_id,
220 6 : spdm_response->vendor_id_len)) {
221 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
222 0 : goto done;
223 : }
224 :
225 6 : if ((spdm_response->header.param1 & SPDM_VENDOR_DEFINED_RESPONSE_LARGE_RESP) !=
226 6 : (spdm_request->header.param1 & SPDM_VENDOR_DEFINED_REQUEST_LARGE_REQ)) {
227 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
228 1 : goto done;
229 : }
230 :
231 5 : if (use_large_payload) {
232 : /* check response buffer size at least spdm response default header plus
233 : * number of bytes required by vendor id and 2 bytes for reserved and 4 bytes
234 : * for large response payload size */
235 3 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t) +
236 3 : spdm_response->vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t)) {
237 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
238 1 : goto done;
239 : }
240 : } else {
241 : /* check response buffer size at least spdm response default header plus
242 : * number of bytes required by vendor id and 2 bytes for response payload size */
243 2 : if (spdm_response_size < sizeof(spdm_vendor_defined_response_msg_t) +
244 2 : spdm_response->vendor_id_len + sizeof(uint16_t)) {
245 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
246 0 : goto done;
247 : }
248 : }
249 :
250 4 : *resp_standard_id = spdm_response->standard_id;
251 4 : if (*resp_vendor_id_len < spdm_response->vendor_id_len) {
252 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
253 0 : goto done;
254 : }
255 4 : *resp_vendor_id_len = spdm_response->vendor_id_len;
256 4 : if ((*resp_vendor_id_len) != 0) {
257 4 : libspdm_copy_mem(resp_vendor_id, *resp_vendor_id_len, spdm_response->vendor_plus_request,
258 4 : *resp_vendor_id_len);
259 : }
260 :
261 : /* -=[Process Response Phase]=- */
262 4 : response_ptr = spdm_response->vendor_plus_request + spdm_response->vendor_id_len;
263 4 : if (use_large_payload) {
264 2 : response_ptr += sizeof(uint16_t);
265 2 : response_size = *((uint32_t*)response_ptr);
266 2 : if (spdm_response_size < response_size +
267 2 : sizeof(spdm_vendor_defined_response_msg_t) +
268 2 : spdm_response->vendor_id_len + sizeof(uint16_t) + sizeof(uint32_t)) {
269 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
270 1 : goto done;
271 : }
272 1 : response_ptr += sizeof(uint32_t);
273 : } else {
274 2 : response_size = *((uint16_t*)response_ptr);
275 :
276 2 : if (spdm_response_size < response_size +
277 2 : sizeof(spdm_vendor_defined_response_msg_t) +
278 2 : spdm_response->vendor_id_len + sizeof(uint16_t)) {
279 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
280 0 : goto done;
281 : }
282 2 : response_ptr += sizeof(uint16_t);
283 : }
284 :
285 3 : if (*resp_size < response_size) {
286 1 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
287 1 : goto done;
288 : }
289 2 : libspdm_copy_mem(resp_data, *resp_size, response_ptr, response_size);
290 2 : *resp_size = response_size;
291 :
292 : /* -=[Log Message Phase]=- */
293 : #if LIBSPDM_ENABLE_MSG_LOG
294 2 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
295 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
296 :
297 2 : status = LIBSPDM_STATUS_SUCCESS;
298 9 : done:
299 9 : libspdm_release_receiver_buffer (spdm_context); /* this will free up response-message, need to find workaround */
300 9 : return status;
301 : }
302 :
303 10 : libspdm_return_t libspdm_vendor_send_request_receive_response(
304 : void *spdm_context,
305 : const uint32_t *session_id,
306 : uint16_t req_standard_id,
307 : uint8_t req_vendor_id_len,
308 : const void *req_vendor_id,
309 : uint32_t req_size,
310 : const void *req_data,
311 : uint16_t *resp_standard_id,
312 : uint8_t *resp_vendor_id_len,
313 : void *resp_vendor_id,
314 : uint32_t *resp_size,
315 : void *resp_data)
316 : {
317 : libspdm_context_t *context;
318 : size_t retry;
319 : uint64_t retry_delay_time;
320 : libspdm_return_t status;
321 :
322 10 : context = spdm_context;
323 10 : context->crypto_request = true;
324 10 : retry = context->retry_times;
325 10 : retry_delay_time = context->retry_delay_time;
326 : do {
327 10 : status = libspdm_try_vendor_send_request_receive_response(
328 : context,
329 : session_id,
330 : req_standard_id,
331 : req_vendor_id_len,
332 : req_vendor_id,
333 : req_size,
334 : req_data,
335 : resp_standard_id,
336 : resp_vendor_id_len,
337 : resp_vendor_id,
338 : resp_size,
339 : resp_data);
340 10 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
341 10 : return status;
342 : }
343 :
344 0 : libspdm_sleep(retry_delay_time);
345 0 : } while (retry-- != 0);
346 :
347 0 : return status;
348 : }
349 :
350 : #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
|