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_responder_lib.h"
8 :
9 : #if LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES
10 :
11 : /* expected number of bytes for VENDOR MESSAGE HEADERS */
12 : #define SPDM_VENDOR_DEFINED_FIXED_HEADER_LEN 7
13 :
14 9 : libspdm_return_t libspdm_register_vendor_get_id_callback_func(void *spdm_context,
15 : libspdm_vendor_get_id_callback_func resp_callback)
16 : {
17 :
18 9 : libspdm_context_t *context = (libspdm_context_t *)spdm_context;
19 9 : context->vendor_response_get_id = resp_callback;
20 9 : return LIBSPDM_STATUS_SUCCESS;
21 : }
22 :
23 10 : libspdm_return_t libspdm_register_vendor_callback_func(void *spdm_context,
24 : libspdm_vendor_response_callback_func resp_callback)
25 : {
26 :
27 10 : libspdm_context_t *context = (libspdm_context_t *)spdm_context;
28 10 : context->vendor_response_callback = resp_callback;
29 10 : return LIBSPDM_STATUS_SUCCESS;
30 : }
31 :
32 11 : libspdm_return_t libspdm_get_vendor_defined_response(libspdm_context_t *spdm_context,
33 : size_t request_size,
34 : const void *request,
35 : size_t *response_size,
36 : void *response)
37 : {
38 : const spdm_vendor_defined_request_msg_t *spdm_request;
39 : spdm_vendor_defined_response_msg_t *spdm_response;
40 : uint16_t header_length;
41 11 : size_t response_capacity = 0;
42 11 : libspdm_return_t status = LIBSPDM_STATUS_SUCCESS;
43 :
44 11 : libspdm_session_info_t *session_info = NULL;
45 11 : libspdm_session_state_t session_state = 0;
46 11 : const uint32_t *session_id = NULL;
47 11 : uint8_t *resp_data = NULL;
48 : const uint8_t *req_vendor_id;
49 : const uint8_t *req_data;
50 11 : uint32_t resp_size = 0;
51 11 : uint32_t req_size = 0;
52 : bool use_large_payload;
53 :
54 : /* -=[Check Parameters Phase]=- */
55 11 : if (request == NULL ||
56 10 : response == NULL ||
57 : response_size == NULL) {
58 1 : return LIBSPDM_STATUS_INVALID_PARAMETER;
59 : }
60 :
61 10 : if (spdm_context->last_spdm_request_session_id_valid) {
62 2 : session_info = libspdm_get_session_info_via_session_id(
63 : spdm_context,
64 : spdm_context->last_spdm_request_session_id);
65 2 : if (session_info == NULL) {
66 0 : return libspdm_generate_error_response(
67 : spdm_context,
68 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
69 : response_size, response);
70 : }
71 2 : session_state = libspdm_secured_message_get_session_state(
72 : session_info->secured_message_context);
73 2 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
74 0 : return libspdm_generate_error_response(
75 : spdm_context,
76 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
77 : response_size, response);
78 : }
79 2 : session_id = &session_info->session_id;
80 : }
81 :
82 : /* Check if caller is using the old Vendor Defined API. */
83 10 : if ((spdm_context->vendor_response_callback == NULL ||
84 8 : spdm_context->vendor_response_get_id == NULL)) {
85 2 : if (spdm_context->get_response_func != NULL) {
86 1 : return ((libspdm_get_response_func)spdm_context->get_response_func)(
87 : spdm_context,
88 : session_id,
89 : false,
90 : request_size,
91 : request,
92 : response_size,
93 : response);
94 : } else
95 1 : return libspdm_generate_error_response(spdm_context,
96 : SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
97 : SPDM_VENDOR_DEFINED_REQUEST,
98 : response_size, response);
99 : }
100 :
101 8 : spdm_request = request;
102 :
103 8 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
104 0 : return libspdm_generate_error_response(spdm_context,
105 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
106 : response_size, response);
107 : }
108 8 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
109 0 : return libspdm_responder_handle_response_state(
110 : spdm_context,
111 0 : spdm_request->header.request_response_code,
112 : response_size, response);
113 : }
114 8 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
115 0 : return libspdm_generate_error_response(spdm_context,
116 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
117 : 0, response_size, response);
118 : }
119 :
120 8 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
121 4 : ((spdm_request->header.param1 & SPDM_VENDOR_DEFINED_REQUEST_LARGE_REQ) != 0)) {
122 4 : if (!libspdm_is_capabilities_flag_supported(
123 : spdm_context, false,
124 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP,
125 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
126 1 : return libspdm_generate_error_response(
127 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
128 : 0, response_size, response);
129 : }
130 3 : use_large_payload = true;
131 : } else {
132 4 : use_large_payload = false;
133 : }
134 :
135 :
136 7 : if (request_size < sizeof(spdm_vendor_defined_request_msg_t)) {
137 0 : return libspdm_generate_error_response(spdm_context,
138 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
139 : response_size, response);
140 : }
141 7 : if (use_large_payload) {
142 3 : if (request_size < sizeof(spdm_vendor_defined_request_msg_t) +
143 3 : spdm_request->len + sizeof(uint16_t) + sizeof(uint32_t)) {
144 1 : return libspdm_generate_error_response(spdm_context,
145 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
146 : response_size, response);
147 : }
148 : } else {
149 4 : if (request_size < sizeof(spdm_vendor_defined_request_msg_t) +
150 4 : spdm_request->len + sizeof(uint16_t)) {
151 2 : return libspdm_generate_error_response(spdm_context,
152 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
153 : response_size, response);
154 : }
155 : }
156 4 : req_vendor_id = ((const uint8_t *)request) + sizeof(spdm_vendor_defined_request_msg_t);
157 :
158 4 : if (use_large_payload) {
159 2 : req_size = libspdm_read_uint32((const uint8_t *)(req_vendor_id + spdm_request->len + sizeof(uint16_t)));
160 2 : if (request_size < sizeof(spdm_vendor_defined_request_msg_t) +
161 2 : spdm_request->len + sizeof(uint16_t) + sizeof(uint32_t) + req_size) {
162 1 : return libspdm_generate_error_response(spdm_context,
163 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
164 : response_size, response);
165 : }
166 : } else {
167 2 : req_size = libspdm_read_uint16((const uint8_t *)(req_vendor_id + spdm_request->len));
168 2 : if (request_size < sizeof(spdm_vendor_defined_request_msg_t) +
169 2 : spdm_request->len + sizeof(uint16_t) + req_size) {
170 1 : return libspdm_generate_error_response(spdm_context,
171 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
172 : response_size, response);
173 : }
174 : }
175 :
176 2 : if (!libspdm_validate_svh_vendor_id_len(spdm_request->standard_id, spdm_request->len)) {
177 0 : return libspdm_generate_error_response(spdm_context,
178 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
179 : response_size, response);
180 : }
181 :
182 2 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
183 2 : spdm_request->header.request_response_code);
184 :
185 : /* length of spdm request/response header before payload start */
186 2 : header_length = sizeof(spdm_vendor_defined_response_msg_t) + spdm_request->len +
187 : sizeof(uint16_t);
188 2 : if (use_large_payload) {
189 1 : header_length += sizeof(uint32_t);
190 : }
191 :
192 2 : LIBSPDM_ASSERT(*response_size >= header_length);
193 : LIBSPDM_ASSERT(
194 : sizeof(spdm_vendor_defined_response_msg_t) == SPDM_VENDOR_DEFINED_FIXED_HEADER_LEN);
195 2 : response_capacity = *response_size - header_length;
196 2 : libspdm_zero_mem(response, header_length);
197 2 : spdm_response = response;
198 :
199 2 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
200 2 : spdm_response->header.request_response_code = SPDM_VENDOR_DEFINED_RESPONSE;
201 2 : spdm_response->header.param1 = 0;
202 2 : spdm_response->header.param2 = 0;
203 :
204 2 : if (use_large_payload) {
205 1 : spdm_response->header.param1 |= SPDM_VENDOR_DEFINED_RESPONSE_LARGE_RESP;
206 : }
207 :
208 : /* SPDM Response format
209 : * 1 byte SPDMVersion
210 : * 1 byte RequestResponseCode
211 : * 2 bytes Reserved
212 : * 2 bytes StandardID
213 : * 1 bytes VendorID Length Len1, based on StandardID
214 : * Len1 bytes VendorID
215 : * if LargeResp == 1
216 : * 2 bytes Reserved
217 : * 4 bytes Response Length Len2
218 : * Len2 bytes Response Payload
219 : * if LargeResp == 0
220 : * 2 bytes Response Length Len2
221 : * Len2 bytes Response Payload
222 : */
223 :
224 : /* replace capacity with size */
225 2 : spdm_response->len = SPDM_MAX_VENDOR_ID_LENGTH;
226 2 : resp_data = ((uint8_t *)response) + sizeof(spdm_vendor_defined_response_msg_t);
227 :
228 2 : if (use_large_payload) {
229 1 : req_data = ((const uint8_t *)request) +
230 : sizeof(spdm_vendor_defined_request_msg_t) +
231 1 : ((const spdm_vendor_defined_request_msg_t*)request)->len +
232 1 : sizeof(uint16_t) + sizeof(uint32_t);
233 : } else {
234 1 : req_data = ((const uint8_t *)request) +
235 : sizeof(spdm_vendor_defined_request_msg_t) +
236 1 : ((const spdm_vendor_defined_request_msg_t*)request)->len +
237 : sizeof(uint16_t);
238 : }
239 :
240 2 : status = spdm_context->vendor_response_get_id(
241 : spdm_context,
242 : session_id,
243 : &spdm_response->standard_id,
244 : &spdm_response->len,
245 : resp_data);
246 :
247 : /* move pointer and adjust buffer size */
248 2 : if (use_large_payload) {
249 1 : resp_data += spdm_response->len + sizeof(uint16_t) + sizeof(uint32_t);
250 1 : response_capacity -= spdm_response->len + sizeof(uint16_t) + sizeof(uint32_t);
251 1 : resp_size = (uint32_t)response_capacity;
252 : } else {
253 1 : resp_data += spdm_response->len + sizeof(uint16_t);
254 1 : response_capacity -= spdm_response->len + sizeof(uint16_t);
255 1 : resp_size = (uint16_t)response_capacity;
256 : }
257 :
258 2 : status = spdm_context->vendor_response_callback(spdm_context,
259 : session_id,
260 2 : spdm_request->standard_id,
261 2 : spdm_request->len,
262 : req_vendor_id, req_size, req_data,
263 : &resp_size,
264 : resp_data);
265 :
266 : /* store back the response payload size */
267 2 : if (use_large_payload) {
268 1 : libspdm_write_uint32((uint8_t *)(resp_data - sizeof(uint32_t)), resp_size);
269 1 : *response_size = resp_size + (size_t)header_length;
270 : } else {
271 1 : libspdm_write_uint16((uint8_t *)(resp_data - sizeof(uint16_t)), (uint16_t)resp_size);
272 1 : *response_size = (uint16_t)resp_size + (size_t)header_length;
273 : }
274 :
275 : LIBSPDM_ASSERT(sizeof(spdm_vendor_defined_request_msg_t) ==
276 : SPDM_VENDOR_DEFINED_FIXED_HEADER_LEN);
277 :
278 2 : return status;
279 : }
280 :
281 : #endif /* LIBSPDM_ENABLE_VENDOR_DEFINED_MESSAGES */
|