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