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 "internal/libspdm_requester_lib.h"
8 : :
9 : : #pragma pack(1)
10 : : typedef struct {
11 : : spdm_message_header_t header;
12 : : uint8_t reserved;
13 : : uint8_t version_number_entry_count;
14 : : spdm_version_number_t version_number_entry[LIBSPDM_MAX_VERSION_COUNT];
15 : : } libspdm_version_response_max_t;
16 : : #pragma pack()
17 : :
18 : : /**
19 : : * This function sends GET_VERSION and receives VERSION.
20 : : *
21 : : * @param spdm_context A pointer to the SPDM context.
22 : : * @param version_number_entry_count The number of SPDM versions that the Responder supports.
23 : : * @param version_number_entry The list of SPDM versions that the Responder supports.
24 : : *
25 : : * @retval LIBSPDM_STATUS_SUCCESS
26 : : * GET_VERSION was sent and VERSION was received.
27 : : * @retval LIBSPDM_STATUS_INVALID_MSG_SIZE
28 : : * The size of the VERSION response is invalid.
29 : : * @retval LIBSPDM_STATUS_INVALID_MSG_FIELD
30 : : * The VERSION response contains one or more invalid fields.
31 : : * @retval LIBSPDM_STATUS_ERROR_PEER
32 : : * The Responder returned an unexpected error.
33 : : * @retval LIBSPDM_STATUS_BUSY_PEER
34 : : * The Responder continually returned Busy error messages.
35 : : * @retval LIBSPDM_STATUS_RESYNCH_PEER
36 : : * The Responder returned a RequestResynch error message.
37 : : * @retval LIBSPDM_STATUS_NEGOTIATION_FAIL
38 : : * The Requester and Responder do not support a common SPDM version.
39 : : **/
40 : 84 : static libspdm_return_t libspdm_try_get_version(libspdm_context_t *spdm_context,
41 : : uint8_t *version_number_entry_count,
42 : : spdm_version_number_t *version_number_entry)
43 : : {
44 : : libspdm_return_t status;
45 : : bool result;
46 : : spdm_get_version_request_t *spdm_request;
47 : : size_t spdm_request_size;
48 : : libspdm_version_response_max_t *spdm_response;
49 : : size_t spdm_response_size;
50 : : spdm_version_number_t common_version;
51 : : uint8_t *message;
52 : : size_t message_size;
53 : : size_t transport_header_size;
54 : :
55 : : /* -=[Set State Phase]=- */
56 : 84 : libspdm_reset_context(spdm_context);
57 : :
58 : : /* -=[Construct Request Phase]=- */
59 : 84 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
60 : 84 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
61 [ + + ]: 84 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
62 : 1 : return status;
63 : : }
64 [ - + ]: 83 : LIBSPDM_ASSERT (message_size >= transport_header_size +
65 : : spdm_context->local_context.capability.transport_tail_size);
66 : 83 : spdm_request = (void *)(message + transport_header_size);
67 : 83 : spdm_request_size = message_size - transport_header_size -
68 : 83 : spdm_context->local_context.capability.transport_tail_size;
69 : :
70 [ - + ]: 83 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_version_request_t));
71 : 83 : spdm_request->header.spdm_version = SPDM_MESSAGE_VERSION_10;
72 : 83 : spdm_request->header.request_response_code = SPDM_GET_VERSION;
73 : 83 : spdm_request->header.param1 = 0;
74 : 83 : spdm_request->header.param2 = 0;
75 : 83 : spdm_request_size = sizeof(spdm_get_version_request_t);
76 : :
77 : : /* -=[Send Request Phase]=- */
78 : 83 : status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
79 [ + + ]: 83 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
80 : 1 : libspdm_release_sender_buffer (spdm_context);
81 : 1 : return status;
82 : : }
83 : 82 : libspdm_release_sender_buffer (spdm_context);
84 : 82 : spdm_request = (void *)spdm_context->last_spdm_request;
85 : :
86 : : /* -=[Receive Response Phase]=- */
87 : 82 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
88 [ + + ]: 82 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
89 : 1 : return status;
90 : : }
91 [ - + ]: 81 : LIBSPDM_ASSERT (message_size >= transport_header_size);
92 : 81 : spdm_response = (void *)(message);
93 : 81 : spdm_response_size = message_size;
94 : :
95 : 81 : status = libspdm_receive_spdm_response(spdm_context, NULL, &spdm_response_size,
96 : : (void **)&spdm_response);
97 [ + + ]: 81 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
98 : 4 : goto receive_done;
99 : : }
100 : :
101 : : /* -=[Validate Response Phase]=- */
102 [ - + ]: 77 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
103 : 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
104 : 0 : goto receive_done;
105 : : }
106 [ + + ]: 77 : if (spdm_response->header.spdm_version != SPDM_MESSAGE_VERSION_10) {
107 : 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
108 : 2 : goto receive_done;
109 : : }
110 [ + + ]: 75 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
111 : : /* Responder shall not respond to the GET_VERSION request message with ErrorCode=ResponseNotReady.*/
112 [ + + ]: 45 : if (spdm_response->header.param1 == SPDM_ERROR_CODE_RESPONSE_NOT_READY) {
113 : : /* Received an unexpected error message. */
114 : 2 : status = LIBSPDM_STATUS_ERROR_PEER;
115 : 2 : goto receive_done;
116 : : }
117 : 43 : status = libspdm_handle_simple_error_response(spdm_context, spdm_response->header.param1);
118 [ + - ]: 43 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
119 : 43 : goto receive_done;
120 : : }
121 [ + + ]: 30 : } else if (spdm_response->header.request_response_code != SPDM_VERSION) {
122 : 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
123 : 2 : goto receive_done;
124 : : }
125 [ + + ]: 28 : if (spdm_response_size < sizeof(spdm_version_response_t)) {
126 : 3 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
127 : 3 : goto receive_done;
128 : : }
129 [ + + ]: 25 : if (spdm_response->version_number_entry_count > LIBSPDM_MAX_VERSION_COUNT) {
130 : 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
131 : 2 : goto receive_done;
132 : : }
133 [ + + ]: 23 : if (spdm_response->version_number_entry_count == 0) {
134 : 2 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
135 : 2 : goto receive_done;
136 : : }
137 : 21 : if (spdm_response_size < sizeof(spdm_version_response_t) +
138 [ + + ]: 21 : spdm_response->version_number_entry_count * sizeof(spdm_version_number_t)) {
139 : 2 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
140 : 2 : goto receive_done;
141 : : }
142 : 19 : spdm_response_size = sizeof(spdm_version_response_t) +
143 : 19 : spdm_response->version_number_entry_count * sizeof(spdm_version_number_t);
144 : :
145 : : /* -=[Process Response Phase]=- */
146 : 19 : status = libspdm_append_message_a(spdm_context, spdm_request, spdm_request_size);
147 [ + + ]: 19 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
148 : 1 : goto receive_done;
149 : : }
150 : :
151 : 18 : status = libspdm_append_message_a(spdm_context, spdm_response, spdm_response_size);
152 [ + + ]: 18 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
153 : 1 : libspdm_reset_message_a(spdm_context);
154 : 1 : goto receive_done;
155 : : }
156 : :
157 : 17 : result = libspdm_negotiate_connection_version (
158 : : &common_version,
159 : 17 : spdm_context->local_context.version.spdm_version,
160 : 17 : spdm_context->local_context.version.spdm_version_count,
161 : 17 : spdm_response->version_number_entry,
162 : 17 : spdm_response->version_number_entry_count);
163 [ + + ]: 17 : if (result == false) {
164 : 2 : libspdm_reset_message_a(spdm_context);
165 : 2 : status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
166 : 2 : goto receive_done;
167 : : }
168 : :
169 : 15 : libspdm_copy_mem(&(spdm_context->connection_info.version),
170 : : sizeof(spdm_context->connection_info.version),
171 : : &(common_version), sizeof(spdm_version_number_t));
172 : :
173 [ + + + - ]: 15 : if (version_number_entry_count != NULL && version_number_entry != NULL) {
174 [ + + ]: 2 : if (*version_number_entry_count < spdm_response->version_number_entry_count) {
175 : 1 : *version_number_entry_count = spdm_response->version_number_entry_count;
176 : 1 : libspdm_reset_message_a(spdm_context);
177 : 1 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
178 : 1 : goto receive_done;
179 : : } else {
180 : 1 : *version_number_entry_count = spdm_response->version_number_entry_count;
181 : 1 : libspdm_copy_mem(version_number_entry,
182 : 1 : spdm_response->version_number_entry_count *
183 : : sizeof(spdm_version_number_t),
184 : 1 : spdm_response->version_number_entry,
185 : 1 : spdm_response->version_number_entry_count *
186 : : sizeof(spdm_version_number_t));
187 : 1 : libspdm_version_number_sort (version_number_entry, *version_number_entry_count);
188 : : }
189 : : }
190 : :
191 : : /* -=[Update State Phase]=- */
192 : 14 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_VERSION;
193 : 14 : status = LIBSPDM_STATUS_SUCCESS;
194 : :
195 : : /* -=[Log Message Phase]=- */
196 : : #if LIBSPDM_ENABLE_MSG_LOG
197 : 14 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
198 : : #endif /* LIBSPDM_ENABLE_MSG_LOG */
199 : :
200 : : /*Set the role of device*/
201 : 14 : spdm_context->local_context.is_requester = true;
202 : :
203 : 81 : receive_done:
204 : 81 : libspdm_release_receiver_buffer (spdm_context);
205 : 81 : return status;
206 : : }
207 : :
208 : 83 : libspdm_return_t libspdm_get_version(libspdm_context_t *spdm_context,
209 : : uint8_t *version_number_entry_count,
210 : : spdm_version_number_t *version_number_entry)
211 : : {
212 : : size_t retry;
213 : : uint64_t retry_delay_time;
214 : : libspdm_return_t status;
215 : :
216 : 83 : spdm_context->crypto_request = false;
217 : 83 : retry = spdm_context->retry_times;
218 : 83 : retry_delay_time = spdm_context->retry_delay_time;
219 : : do {
220 : 84 : status = libspdm_try_get_version(spdm_context,
221 : : version_number_entry_count, version_number_entry);
222 [ + + ]: 84 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
223 : 81 : return status;
224 : : }
225 : :
226 : 3 : libspdm_sleep(retry_delay_time);
227 [ + + ]: 3 : } while (retry-- != 0);
228 : :
229 : 2 : return status;
230 : : }
|