Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 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_CAPABILITY_ENCAP_CAP) && (LIBSPDM_EVENT_RECIPIENT_SUPPORT)
10 :
11 13 : static bool validate_dmtf_event_type(uint16_t event_type_id, uint16_t event_detail_len)
12 : {
13 13 : switch (event_type_id) {
14 7 : case SPDM_DMTF_EVENT_TYPE_EVENT_LOST:
15 7 : return (event_detail_len == SPDM_DMTF_EVENT_TYPE_EVENT_LOST_SIZE);
16 1 : case SPDM_DMTF_EVENT_TYPE_MEASUREMENT_CHANGED:
17 1 : return (event_detail_len == SPDM_DMTF_EVENT_TYPE_MEASUREMENT_CHANGED_SIZE);
18 1 : case SPDM_DMTF_EVENT_TYPE_MEASUREMENT_PRE_UPDATE:
19 1 : return (event_detail_len == SPDM_DMTF_EVENT_TYPE_MEASUREMENT_PRE_UPDATE_SIZE);
20 4 : case SPDM_DMTF_EVENT_TYPE_CERTIFICATE_CHANGED:
21 4 : return (event_detail_len == SPDM_DMTF_EVENT_TYPE_CERTIFICATE_CHANGED_SIZE);
22 0 : default:
23 0 : return false;
24 : }
25 : }
26 :
27 9 : static bool parse_and_send_event(libspdm_context_t *context, uint32_t session_id,
28 : void *event_data, void **next_event_data)
29 : {
30 : libspdm_return_t status;
31 : uint8_t *ptr;
32 : uint32_t event_instance_id;
33 : uint8_t svh_id;
34 : uint8_t svh_vendor_id_len;
35 : void *svh_vendor_id;
36 : uint16_t event_type_id;
37 : uint16_t event_detail_len;
38 :
39 9 : LIBSPDM_ASSERT(context->process_event != NULL);
40 :
41 9 : ptr = event_data;
42 9 : event_instance_id = libspdm_read_uint32(ptr);
43 :
44 9 : ptr += sizeof(uint32_t);
45 9 : ptr += sizeof(uint32_t);
46 9 : svh_id = *ptr;
47 9 : ptr++;
48 9 : svh_vendor_id_len = *ptr;
49 9 : ptr++;
50 :
51 9 : if (svh_vendor_id_len == 0) {
52 9 : svh_vendor_id = NULL;
53 : } else {
54 0 : svh_vendor_id = ptr;
55 : }
56 9 : ptr += svh_vendor_id_len;
57 :
58 9 : event_type_id = libspdm_read_uint16(ptr);
59 9 : ptr += sizeof(uint16_t);
60 9 : event_detail_len = libspdm_read_uint16(ptr);
61 9 : ptr += sizeof(uint16_t);
62 :
63 9 : status = context->process_event(context, session_id, event_instance_id, svh_id,
64 : svh_vendor_id_len, svh_vendor_id, event_type_id,
65 : event_detail_len, ptr);
66 :
67 9 : if (next_event_data != NULL) {
68 7 : ptr += event_detail_len;
69 7 : *next_event_data = ptr;
70 : }
71 :
72 9 : return (status == LIBSPDM_STATUS_SUCCESS);
73 : }
74 :
75 4 : static void *find_event_instance_id(void *events_list_start, uint32_t event_count,
76 : uint32_t target_event_instance_id)
77 : {
78 : uint32_t index;
79 : uint8_t *ptr;
80 :
81 4 : ptr = events_list_start;
82 :
83 6 : for (index = 0; index < event_count; index++) {
84 : uint32_t event_instance_id;
85 :
86 6 : event_instance_id = libspdm_read_uint32(ptr);
87 :
88 6 : if (event_instance_id == target_event_instance_id) {
89 4 : return ptr;
90 : } else {
91 : uint8_t vendor_id_len;
92 : uint16_t event_detail_len;
93 :
94 2 : ptr += sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t);
95 2 : vendor_id_len = *ptr;
96 2 : ptr += sizeof(uint8_t);
97 2 : ptr += vendor_id_len;
98 2 : ptr += sizeof(uint16_t);
99 2 : event_detail_len = libspdm_read_uint16(ptr);
100 2 : ptr += sizeof(uint16_t);
101 2 : ptr += event_detail_len;
102 : }
103 : }
104 :
105 0 : return NULL;
106 : }
107 :
108 48 : static bool check_for_space(const uint8_t *ptr, const uint8_t *end_ptr, size_t increment)
109 : {
110 48 : LIBSPDM_ASSERT(ptr <= end_ptr);
111 :
112 48 : return ((uintptr_t)(end_ptr - ptr) >= increment);
113 : }
114 :
115 8 : libspdm_return_t libspdm_get_encap_response_event_ack(void *spdm_context,
116 : size_t request_size,
117 : void *request,
118 : size_t *response_size,
119 : void *response)
120 : {
121 : spdm_send_event_request_t *spdm_request;
122 : spdm_event_ack_response_t *spdm_response;
123 : libspdm_context_t *context;
124 : uint32_t session_id;
125 : libspdm_session_info_t *session_info;
126 : libspdm_session_state_t session_state;
127 : uint64_t index;
128 : uint32_t prev_event_instance_id;
129 : uint32_t event_instance_id_min;
130 : uint32_t event_instance_id_max;
131 : bool events_list_is_sequential;
132 : uint8_t *ptr;
133 8 : const uint8_t *end_ptr = (uint8_t *)request + request_size;
134 : size_t calculated_request_size;
135 :
136 8 : context = spdm_context;
137 8 : spdm_request = request;
138 :
139 8 : if (libspdm_get_connection_version(context) < SPDM_MESSAGE_VERSION_13) {
140 0 : return libspdm_generate_encap_error_response(
141 : context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, SPDM_SEND_EVENT, response_size, response);
142 : }
143 8 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(context)) {
144 0 : return libspdm_generate_encap_error_response(
145 : context, SPDM_ERROR_CODE_VERSION_MISMATCH, 0, response_size, response);
146 : }
147 8 : if (!libspdm_is_capabilities_flag_supported(
148 : context, true, 0, SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP)) {
149 0 : return libspdm_generate_encap_error_response(
150 : context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST, SPDM_SEND_EVENT, response_size, response);
151 : }
152 8 : if (!context->last_spdm_request_session_id_valid) {
153 0 : return libspdm_generate_encap_error_response(
154 : context, SPDM_ERROR_CODE_SESSION_REQUIRED, 0, response_size, response);
155 : }
156 :
157 8 : session_id = context->last_spdm_request_session_id;
158 8 : session_info = libspdm_get_session_info_via_session_id(context, session_id);
159 8 : if (session_info == NULL) {
160 0 : return libspdm_generate_encap_error_response(
161 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
162 : }
163 :
164 8 : session_state = libspdm_secured_message_get_session_state(
165 : session_info->secured_message_context);
166 8 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
167 0 : return libspdm_generate_encap_error_response(
168 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
169 : }
170 :
171 8 : libspdm_reset_message_buffer_via_request_code(context, NULL,
172 8 : spdm_request->header.request_response_code);
173 :
174 8 : if (!check_for_space((uint8_t *)request, end_ptr, sizeof(spdm_send_event_request_t))) {
175 0 : return libspdm_generate_encap_error_response(
176 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
177 : }
178 :
179 8 : if (spdm_request->event_count == 0) {
180 1 : return libspdm_generate_encap_error_response(
181 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
182 : }
183 :
184 7 : ptr = (uint8_t *)(spdm_request + 1);
185 :
186 7 : event_instance_id_min = UINT32_MAX;
187 7 : event_instance_id_max = 0;
188 7 : events_list_is_sequential = true;
189 :
190 7 : calculated_request_size = sizeof(spdm_send_event_request_t);
191 :
192 : /* Parse and validate all events for size and fields. */
193 20 : for (index = 0; index < spdm_request->event_count; index++) {
194 : uint32_t event_instance_id;
195 : uint8_t svh_id;
196 : uint8_t svh_vendor_id_len;
197 : uint16_t event_type_id;
198 : uint16_t event_detail_len;
199 :
200 14 : if (!check_for_space(ptr, end_ptr,
201 : sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t) +
202 : sizeof(uint8_t))) {
203 1 : return libspdm_generate_encap_error_response(
204 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
205 : }
206 :
207 13 : event_instance_id = libspdm_read_uint32(ptr);
208 :
209 13 : if ((index != 0) && events_list_is_sequential) {
210 6 : if (event_instance_id != (prev_event_instance_id + 1)) {
211 2 : events_list_is_sequential = false;
212 : }
213 : }
214 13 : if (event_instance_id < event_instance_id_min) {
215 8 : event_instance_id_min = event_instance_id;
216 : }
217 13 : if (event_instance_id > event_instance_id_max) {
218 12 : event_instance_id_max = event_instance_id;
219 : }
220 13 : prev_event_instance_id = event_instance_id;
221 :
222 13 : ptr += sizeof(uint32_t) + sizeof(uint32_t);
223 13 : svh_id = *ptr;
224 13 : ptr += sizeof(uint8_t);
225 13 : svh_vendor_id_len = *ptr;
226 13 : ptr += sizeof(uint8_t);
227 :
228 13 : if (!libspdm_validate_svh_vendor_id_len(svh_id, svh_vendor_id_len)) {
229 0 : return libspdm_generate_encap_error_response(
230 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
231 : }
232 :
233 13 : if (!check_for_space(ptr, end_ptr,
234 13 : (size_t)svh_vendor_id_len + sizeof(uint16_t) + sizeof(uint16_t))) {
235 0 : return libspdm_generate_encap_error_response(
236 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
237 : }
238 :
239 13 : ptr += svh_vendor_id_len;
240 :
241 13 : event_type_id = libspdm_read_uint16(ptr);
242 13 : ptr += sizeof(uint16_t);
243 13 : event_detail_len = libspdm_read_uint16(ptr);
244 13 : ptr += sizeof(uint16_t);
245 :
246 13 : if (svh_id == SPDM_REGISTRY_ID_DMTF) {
247 13 : if (!validate_dmtf_event_type(event_type_id, event_detail_len)) {
248 0 : return libspdm_generate_encap_error_response(
249 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
250 : }
251 : }
252 :
253 13 : if (!check_for_space(ptr, end_ptr, (size_t)event_detail_len)) {
254 0 : return libspdm_generate_encap_error_response(
255 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
256 : }
257 :
258 13 : ptr += event_detail_len;
259 13 : calculated_request_size += sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint8_t) +
260 13 : sizeof(uint8_t) + (size_t)svh_vendor_id_len + sizeof(uint16_t) +
261 13 : sizeof(uint16_t) + (size_t)event_detail_len;
262 : }
263 :
264 : /* Event must be sent in a secure session so message size can be calculated exactly. */
265 6 : if (request_size != calculated_request_size) {
266 1 : return libspdm_generate_encap_error_response(
267 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
268 : }
269 :
270 : /* If event instance IDs are not sequential then ensure there are no gaps or duplicates before
271 : * sending individual events to Integrator. */
272 5 : if (!events_list_is_sequential) {
273 2 : void *event_data = spdm_request + 1;
274 :
275 2 : if ((event_instance_id_max - event_instance_id_min + 1) != spdm_request->event_count) {
276 1 : return libspdm_generate_encap_error_response(
277 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
278 : }
279 :
280 3 : for (index = 0; index < spdm_request->event_count; index++) {
281 2 : if (find_event_instance_id(event_data, spdm_request->event_count,
282 2 : event_instance_id_min + (uint32_t)index) == NULL) {
283 0 : return libspdm_generate_encap_error_response(
284 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
285 : }
286 : }
287 : }
288 :
289 4 : if (context->process_event != NULL) {
290 4 : void *next_event_data = spdm_request + 1;
291 :
292 13 : for (index = 0; index < spdm_request->event_count; index++) {
293 9 : if (events_list_is_sequential) {
294 7 : if (!parse_and_send_event(context, session_id, next_event_data, &next_event_data)) {
295 0 : return libspdm_generate_encap_error_response(
296 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
297 : }
298 : } else {
299 : void *event_data;
300 :
301 2 : event_data = find_event_instance_id(next_event_data, spdm_request->event_count,
302 2 : event_instance_id_min + (uint32_t)index);
303 2 : if (event_data == NULL) {
304 0 : return libspdm_generate_encap_error_response(
305 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
306 : }
307 :
308 2 : if (!parse_and_send_event(context, session_id, event_data, NULL)) {
309 0 : return libspdm_generate_encap_error_response(
310 : context, SPDM_ERROR_CODE_INVALID_REQUEST, 0, response_size, response);
311 : }
312 : }
313 : }
314 : }
315 :
316 4 : spdm_response = response;
317 :
318 4 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
319 4 : spdm_response->header.request_response_code = SPDM_EVENT_ACK;
320 4 : spdm_response->header.param1 = 0;
321 4 : spdm_response->header.param2 = 0;
322 :
323 4 : *response_size = sizeof(spdm_event_ack_response_t);
324 :
325 4 : return LIBSPDM_STATUS_SUCCESS;
326 : }
327 :
328 : #endif /* (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (LIBSPDM_EVENT_RECIPIENT_SUPPORT) */
|