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