Branch data Line data Source code
1 : : /**
2 : : * Copyright Notice:
3 : : * Copyright 2021-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 "library/spdm_transport_pcidoe_lib.h"
8 : : #include "industry_standard/pcidoe.h"
9 : : #include "internal/libspdm_common_lib.h"
10 : : #include "hal/library/debuglib.h"
11 : : #include "hal/library/memlib.h"
12 : :
13 : 0 : uint8_t libspdm_pci_doe_get_sequence_number(uint64_t sequence_number,
14 : : uint8_t *sequence_number_buffer)
15 : : {
16 : 0 : libspdm_copy_mem(sequence_number_buffer, LIBSPDM_PCI_DOE_SEQUENCE_NUMBER_COUNT,
17 : : &sequence_number, LIBSPDM_PCI_DOE_SEQUENCE_NUMBER_COUNT);
18 : 0 : return LIBSPDM_PCI_DOE_SEQUENCE_NUMBER_COUNT;
19 : : }
20 : :
21 : 0 : uint32_t libspdm_pci_doe_get_max_random_number_count(void)
22 : : {
23 : 0 : return LIBSPDM_PCI_DOE_MAX_RANDOM_NUMBER_COUNT;
24 : : }
25 : :
26 : 0 : spdm_version_number_t libspdm_pci_doe_get_secured_spdm_version(
27 : : spdm_version_number_t secured_message_version)
28 : : {
29 : : /* PCI-SIG uses DSP0277 version */
30 : 0 : return secured_message_version;
31 : : }
32 : :
33 : : /**
34 : : * Encode a normal message or secured message to a transport message.
35 : : *
36 : : * @param session_id Indicates if it is a secured message protected via SPDM session.
37 : : * If session_id is NULL, it is a normal message.
38 : : * If session_id is NOT NULL, it is a secured message.
39 : : * @param message_size size in bytes of the message data buffer.
40 : : * @param message A pointer to a source buffer to store the message.
41 : : * @param transport_message_size size in bytes of the transport message data buffer.
42 : : * @param transport_message A pointer to a destination buffer to store the transport message.
43 : : **/
44 : 1 : libspdm_return_t libspdm_pci_doe_encode_message(const uint32_t *session_id,
45 : : size_t message_size, void *message,
46 : : size_t *transport_message_size,
47 : : void **transport_message)
48 : : {
49 : : size_t aligned_message_size;
50 : : size_t alignment;
51 : : uint32_t data32;
52 : : pci_doe_data_object_header_t *pci_doe_header;
53 : :
54 : 1 : alignment = LIBSPDM_PCI_DOE_ALIGNMENT;
55 : 1 : aligned_message_size =
56 : 1 : (message_size + (alignment - 1)) & ~(alignment - 1);
57 : :
58 [ - + ]: 1 : LIBSPDM_ASSERT(*transport_message_size >=
59 : : aligned_message_size + sizeof(pci_doe_data_object_header_t));
60 : 1 : if (*transport_message_size <
61 [ - + ]: 1 : aligned_message_size + sizeof(pci_doe_data_object_header_t)) {
62 : 0 : *transport_message_size = aligned_message_size +
63 : : sizeof(pci_doe_data_object_header_t);
64 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
65 : : }
66 : 1 : *transport_message_size =
67 : 1 : aligned_message_size + sizeof(pci_doe_data_object_header_t);
68 : 1 : *transport_message = (uint8_t *)message - sizeof(pci_doe_data_object_header_t);
69 : 1 : pci_doe_header = *transport_message;
70 : 1 : pci_doe_header->vendor_id = PCI_DOE_VENDOR_ID_PCISIG;
71 [ - + ]: 1 : if (session_id != NULL) {
72 : 0 : pci_doe_header->data_object_type =
73 : : PCI_DOE_DATA_OBJECT_TYPE_SECURED_SPDM;
74 : 0 : data32 = libspdm_read_uint32((const uint8_t *)message);
75 [ # # ]: 0 : LIBSPDM_ASSERT(*session_id == data32);
76 [ # # ]: 0 : if (*session_id != data32) {
77 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
78 : : }
79 : : } else {
80 : 1 : pci_doe_header->data_object_type =
81 : : PCI_DOE_DATA_OBJECT_TYPE_SPDM;
82 : : }
83 : 1 : pci_doe_header->reserved = 0;
84 [ - + ]: 1 : if (*transport_message_size > PCI_DOE_MAX_SIZE_IN_BYTE) {
85 : 0 : return LIBSPDM_STATUS_BUFFER_FULL;
86 [ - + ]: 1 : } else if (*transport_message_size == PCI_DOE_MAX_SIZE_IN_BYTE) {
87 : 0 : pci_doe_header->length = 0;
88 : : } else {
89 : 1 : pci_doe_header->length =
90 : 1 : (uint32_t)*transport_message_size / sizeof(uint32_t);
91 : : }
92 : :
93 : 1 : libspdm_zero_mem((uint8_t *)message + message_size,
94 : : aligned_message_size - message_size);
95 : 1 : return LIBSPDM_STATUS_SUCCESS;
96 : : }
97 : :
98 : 0 : libspdm_return_t libspdm_pci_doe_encode_discovery(size_t message_size, void *message,
99 : : size_t *transport_message_size,
100 : : void **transport_message)
101 : : {
102 : : size_t aligned_message_size;
103 : : size_t alignment;
104 : : pci_doe_data_object_header_t *pci_doe_header;
105 : :
106 : 0 : alignment = LIBSPDM_PCI_DOE_ALIGNMENT;
107 : 0 : aligned_message_size =
108 : 0 : (message_size + (alignment - 1)) & ~(alignment - 1);
109 : :
110 [ # # ]: 0 : LIBSPDM_ASSERT(*transport_message_size >=
111 : : aligned_message_size + sizeof(pci_doe_data_object_header_t));
112 : 0 : if (*transport_message_size <
113 [ # # ]: 0 : aligned_message_size + sizeof(pci_doe_data_object_header_t)) {
114 : 0 : *transport_message_size = aligned_message_size +
115 : : sizeof(pci_doe_data_object_header_t);
116 : 0 : return LIBSPDM_STATUS_BUFFER_TOO_SMALL;
117 : : }
118 : :
119 : 0 : *transport_message_size =
120 : 0 : aligned_message_size + sizeof(pci_doe_data_object_header_t);
121 : 0 : *transport_message = (uint8_t *)message - sizeof(pci_doe_data_object_header_t);
122 : 0 : pci_doe_header = *transport_message;
123 : 0 : pci_doe_header->vendor_id = PCI_DOE_VENDOR_ID_PCISIG;
124 : 0 : pci_doe_header->data_object_type = PCI_DOE_DATA_OBJECT_TYPE_DOE_DISCOVERY;
125 : 0 : pci_doe_header->reserved = 0;
126 : :
127 [ # # ]: 0 : if (*transport_message_size > PCI_DOE_MAX_SIZE_IN_BYTE) {
128 : 0 : return LIBSPDM_STATUS_BUFFER_FULL;
129 [ # # ]: 0 : } else if (*transport_message_size == PCI_DOE_MAX_SIZE_IN_BYTE) {
130 : 0 : pci_doe_header->length = 0;
131 : : } else {
132 : 0 : pci_doe_header->length =
133 : 0 : (uint32_t)*transport_message_size / sizeof(uint32_t);
134 : : }
135 : :
136 : 0 : libspdm_zero_mem((uint8_t *)message + message_size,
137 : : aligned_message_size - message_size);
138 : :
139 : 0 : return LIBSPDM_STATUS_SUCCESS;
140 : : }
141 : :
142 : : /**
143 : : * Decode a transport message to a normal message or secured message.
144 : : *
145 : : * @param session_id Indicates if it is a secured message protected via SPDM session.
146 : : * If *session_id is NULL, it is a normal message.
147 : : * If *session_id is NOT NULL, it is a secured message.
148 : : * @param transport_message_size size in bytes of the transport message data buffer.
149 : : * @param transport_message A pointer to a source buffer to store the transport message.
150 : : * @param message_size size in bytes of the message data buffer.
151 : : * @param message A pointer to a destination buffer to store the message.
152 : : **/
153 : 0 : libspdm_return_t libspdm_pci_doe_decode_message(uint32_t **session_id,
154 : : size_t transport_message_size,
155 : : void *transport_message,
156 : : size_t *message_size,
157 : : void **message)
158 : : {
159 : : const pci_doe_data_object_header_t *pci_doe_header;
160 : : uint32_t length;
161 : :
162 [ # # ]: 0 : LIBSPDM_ASSERT(transport_message_size > sizeof(pci_doe_data_object_header_t));
163 [ # # ]: 0 : if (transport_message_size <= sizeof(pci_doe_data_object_header_t)) {
164 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
165 : : }
166 : :
167 : 0 : pci_doe_header = transport_message;
168 [ # # ]: 0 : if (pci_doe_header->vendor_id != PCI_DOE_VENDOR_ID_PCISIG) {
169 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
170 : : }
171 : :
172 [ # # # ]: 0 : switch (pci_doe_header->data_object_type) {
173 : 0 : case PCI_DOE_DATA_OBJECT_TYPE_SECURED_SPDM:
174 [ # # ]: 0 : LIBSPDM_ASSERT(session_id != NULL);
175 [ # # ]: 0 : if (session_id == NULL) {
176 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
177 : : }
178 [ # # ]: 0 : if (transport_message_size <=
179 : : sizeof(pci_doe_data_object_header_t) + sizeof(uint32_t)) {
180 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
181 : : }
182 : 0 : *session_id = (void *)((uint8_t *)transport_message +
183 : : sizeof(pci_doe_data_object_header_t));
184 : 0 : break;
185 : 0 : case PCI_DOE_DATA_OBJECT_TYPE_SPDM:
186 [ # # ]: 0 : if (session_id != NULL) {
187 : 0 : *session_id = NULL;
188 : : }
189 : 0 : break;
190 : 0 : default:
191 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
192 : : }
193 : :
194 [ # # ]: 0 : if (pci_doe_header->reserved != 0) {
195 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
196 : : }
197 [ # # ]: 0 : if (pci_doe_header->length >= PCI_DOE_MAX_SIZE_IN_DW) {
198 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
199 [ # # ]: 0 : } else if (pci_doe_header->length == 0) {
200 : 0 : length = PCI_DOE_MAX_SIZE_IN_BYTE;
201 : : } else {
202 : 0 : length = pci_doe_header->length * sizeof(uint32_t);
203 : : }
204 [ # # ]: 0 : if (length != transport_message_size) {
205 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
206 : : }
207 : :
208 [ # # ]: 0 : LIBSPDM_ASSERT(((transport_message_size - sizeof(pci_doe_data_object_header_t)) &
209 : : (LIBSPDM_PCI_DOE_ALIGNMENT - 1)) == 0);
210 : :
211 : 0 : *message_size = transport_message_size - sizeof(pci_doe_data_object_header_t);
212 : 0 : *message = (uint8_t *)transport_message + sizeof(pci_doe_data_object_header_t);
213 : 0 : return LIBSPDM_STATUS_SUCCESS;
214 : : }
215 : :
216 : 0 : libspdm_return_t libspdm_pci_doe_decode_discovery_request(size_t transport_message_size,
217 : : const void *transport_message,
218 : : uint8_t *index)
219 : : {
220 : : const pci_doe_data_object_header_t *pci_doe_header;
221 : : uint32_t length;
222 : : const uint8_t *message;
223 : :
224 [ # # ]: 0 : LIBSPDM_ASSERT(transport_message_size > sizeof(pci_doe_data_object_header_t));
225 [ # # ]: 0 : if (transport_message_size <= sizeof(pci_doe_data_object_header_t)) {
226 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
227 : : }
228 : :
229 : 0 : pci_doe_header = transport_message;
230 [ # # ]: 0 : if (pci_doe_header->vendor_id != PCI_DOE_VENDOR_ID_PCISIG) {
231 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
232 : : }
233 : :
234 [ # # ]: 0 : switch (pci_doe_header->data_object_type) {
235 : 0 : case PCI_DOE_DATA_OBJECT_TYPE_DOE_DISCOVERY:
236 : : /*
237 : : * Check to see if we received a DOE discovery message.
238 : : * DOE discovery is not part of the SPDM spec, instead it's part
239 : : * of the PCIe DOE spec. DOE discovery is mandatory for all
240 : : * implementations.
241 : : */
242 : 0 : message = (const uint8_t *)transport_message + sizeof(pci_doe_data_object_header_t);
243 [ # # ]: 0 : if (index != NULL) {
244 : 0 : *index = *message;
245 : : }
246 : 0 : break;
247 : 0 : default:
248 : 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
249 : : }
250 : :
251 [ # # ]: 0 : if (pci_doe_header->reserved != 0) {
252 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
253 : : }
254 [ # # ]: 0 : if (pci_doe_header->length >= PCI_DOE_MAX_SIZE_IN_DW) {
255 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
256 [ # # ]: 0 : } else if (pci_doe_header->length == 0) {
257 : 0 : length = PCI_DOE_MAX_SIZE_IN_BYTE;
258 : : } else {
259 : 0 : length = pci_doe_header->length * sizeof(uint32_t);
260 : : }
261 [ # # ]: 0 : if (length != transport_message_size) {
262 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
263 : : }
264 : :
265 : 0 : return LIBSPDM_STATUS_SUCCESS;
266 : : }
267 : :
268 : 0 : libspdm_return_t libspdm_pci_doe_decode_discovery_request_version(size_t transport_message_size,
269 : : const void *transport_message,
270 : : uint8_t *version)
271 : : {
272 : : const uint8_t *message;
273 : : libspdm_return_t status;
274 : :
275 : : /*
276 : : * Calling libspdm_pci_doe_decode_discovery_request to check the format of transport_message.
277 : : * So that the duplicated checking code is skipped.
278 : : */
279 : 0 : status = libspdm_pci_doe_decode_discovery_request(transport_message_size, transport_message,
280 : : NULL);
281 [ # # ]: 0 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
282 : 0 : return status;
283 : : }
284 : :
285 : : /*
286 : : * DOE discovery is not part of the SPDM spec, instead it's part
287 : : * of the PCIe DOE spec. DOE discovery is mandatory for all
288 : : * implementations.
289 : : *
290 : : * DOE Discovery Version is introduced in PCIe Spec 6.1 Section 6.30.1.1.
291 : : * It is Byte-1 in DOE discovery request.
292 : : */
293 : 0 : message = (const uint8_t *)transport_message + sizeof(pci_doe_data_object_header_t) + 1;
294 [ # # ]: 0 : if (version != NULL) {
295 : 0 : *version = *message;
296 : : }
297 : :
298 : 0 : return LIBSPDM_STATUS_SUCCESS;
299 : : }
300 : :
301 : 1 : libspdm_return_t libspdm_pci_doe_decode_discovery_response(size_t transport_message_size,
302 : : void *transport_message,
303 : : uint16_t *vendor_id,
304 : : uint8_t *protocol,
305 : : uint8_t *next_index)
306 : : {
307 : : const pci_doe_data_object_header_t *pci_doe_header;
308 : : uint32_t length;
309 : : uint8_t *message;
310 : :
311 [ - + ]: 1 : LIBSPDM_ASSERT(transport_message_size > sizeof(pci_doe_data_object_header_t));
312 [ - + ]: 1 : if (transport_message_size <= sizeof(pci_doe_data_object_header_t)) {
313 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
314 : : }
315 : :
316 : 1 : pci_doe_header = transport_message;
317 [ - + ]: 1 : if (pci_doe_header->vendor_id != PCI_DOE_VENDOR_ID_PCISIG) {
318 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
319 : : }
320 : :
321 [ - + ]: 1 : switch (pci_doe_header->data_object_type) {
322 : 0 : case PCI_DOE_DATA_OBJECT_TYPE_DOE_DISCOVERY:
323 : : /*
324 : : * Check to see if we received a DOE discovery message.
325 : : * DOE discovery is not part of the SPDM spec, instead it's part
326 : : * of the PCIe DOE spec. DOE discovery is mandatory for all
327 : : * implementations.
328 : : */
329 [ # # ]: 0 : if (transport_message_size <
330 : : sizeof(pci_doe_data_object_header_t) + sizeof(pci_doe_discovery_response_t)) {
331 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
332 : : }
333 : 0 : message = (uint8_t *)transport_message + sizeof(pci_doe_data_object_header_t);
334 [ # # ]: 0 : if (vendor_id != NULL) {
335 : 0 : *vendor_id = *message;
336 : : }
337 [ # # ]: 0 : if (protocol != NULL) {
338 : 0 : *protocol = *(message + sizeof(uint16_t));
339 : : }
340 [ # # ]: 0 : if (next_index != NULL) {
341 : 0 : *next_index = *(message + sizeof(uint16_t) + sizeof(uint8_t));
342 : : }
343 : 0 : break;
344 : 1 : default:
345 : 1 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
346 : : }
347 : :
348 [ # # ]: 0 : if (pci_doe_header->reserved != 0) {
349 : 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
350 : : }
351 [ # # ]: 0 : if (pci_doe_header->length >= PCI_DOE_MAX_SIZE_IN_DW) {
352 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
353 [ # # ]: 0 : } else if (pci_doe_header->length == 0) {
354 : 0 : length = PCI_DOE_MAX_SIZE_IN_BYTE;
355 : : } else {
356 : 0 : length = pci_doe_header->length * sizeof(uint32_t);
357 : : }
358 [ # # ]: 0 : if (length != transport_message_size) {
359 : 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
360 : : }
361 : :
362 : 0 : return LIBSPDM_STATUS_SUCCESS;
363 : : }
364 : :
365 : 0 : uint32_t libspdm_transport_pci_doe_get_header_size(
366 : : void *spdm_context)
367 : : {
368 : 0 : return sizeof(pci_doe_data_object_header_t) + sizeof(spdm_secured_message_cipher_header_t);
369 : : }
|