Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2024 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_count The number of SPDM versions that the Responder supports.
23 : * @param VersionNumberEntries 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 39 : 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 39 : libspdm_reset_message_a(spdm_context);
57 39 : libspdm_reset_message_d(spdm_context);
58 39 : libspdm_reset_message_b(spdm_context);
59 39 : libspdm_reset_message_c(spdm_context);
60 39 : libspdm_reset_context(spdm_context);
61 39 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL, SPDM_GET_VERSION);
62 :
63 : /* -=[Construct Request Phase]=- */
64 39 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
65 39 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
66 39 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
67 1 : return status;
68 : }
69 38 : LIBSPDM_ASSERT (message_size >= transport_header_size +
70 : spdm_context->local_context.capability.transport_tail_size);
71 38 : spdm_request = (void *)(message + transport_header_size);
72 38 : spdm_request_size = message_size - transport_header_size -
73 38 : spdm_context->local_context.capability.transport_tail_size;
74 :
75 38 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_version_request_t));
76 38 : spdm_request->header.spdm_version = SPDM_MESSAGE_VERSION_10;
77 38 : spdm_request->header.request_response_code = SPDM_GET_VERSION;
78 38 : spdm_request->header.param1 = 0;
79 38 : spdm_request->header.param2 = 0;
80 38 : spdm_request_size = sizeof(spdm_get_version_request_t);
81 :
82 : /* -=[Send Request Phase]=- */
83 38 : status = libspdm_send_spdm_request(spdm_context, NULL, spdm_request_size, spdm_request);
84 38 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
85 1 : libspdm_release_sender_buffer (spdm_context);
86 1 : return status;
87 : }
88 37 : libspdm_release_sender_buffer (spdm_context);
89 37 : spdm_request = (void *)spdm_context->last_spdm_request;
90 :
91 : /* -=[Receive Response Phase]=- */
92 37 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
93 37 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
94 1 : return status;
95 : }
96 36 : LIBSPDM_ASSERT (message_size >= transport_header_size);
97 36 : spdm_response = (void *)(message);
98 36 : spdm_response_size = message_size;
99 :
100 36 : status = libspdm_receive_spdm_response(spdm_context, NULL, &spdm_response_size,
101 : (void **)&spdm_response);
102 36 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
103 1 : goto receive_done;
104 : }
105 :
106 : /* -=[Validate Response Phase]=- */
107 35 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
108 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
109 0 : goto receive_done;
110 : }
111 35 : if (spdm_response->header.spdm_version != SPDM_MESSAGE_VERSION_10) {
112 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
113 1 : goto receive_done;
114 : }
115 34 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
116 : /* Responder shall not respond to the GET_VERSION request message with ErrorCode=ResponseNotReady.*/
117 23 : if (spdm_response->header.param1 == SPDM_ERROR_CODE_RESPONSE_NOT_READY) {
118 : /* Received an unexpected error message. */
119 1 : status = LIBSPDM_STATUS_ERROR_PEER;
120 1 : goto receive_done;
121 : }
122 22 : status = libspdm_handle_simple_error_response(spdm_context, spdm_response->header.param1);
123 22 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
124 22 : goto receive_done;
125 : }
126 11 : } else if (spdm_response->header.request_response_code != SPDM_VERSION) {
127 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
128 1 : goto receive_done;
129 : }
130 10 : if (spdm_response_size < sizeof(spdm_version_response_t)) {
131 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
132 1 : goto receive_done;
133 : }
134 9 : if (spdm_response->version_number_entry_count > LIBSPDM_MAX_VERSION_COUNT) {
135 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
136 1 : goto receive_done;
137 : }
138 8 : if (spdm_response->version_number_entry_count == 0) {
139 1 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
140 1 : goto receive_done;
141 : }
142 7 : if (spdm_response_size < sizeof(spdm_version_response_t) +
143 7 : spdm_response->version_number_entry_count * sizeof(spdm_version_number_t)) {
144 1 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
145 1 : goto receive_done;
146 : }
147 6 : spdm_response_size = sizeof(spdm_version_response_t) +
148 6 : spdm_response->version_number_entry_count * sizeof(spdm_version_number_t);
149 :
150 : /* -=[Process Response Phase]=- */
151 6 : status = libspdm_append_message_a(spdm_context, spdm_request, spdm_request_size);
152 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
153 0 : goto receive_done;
154 : }
155 :
156 6 : status = libspdm_append_message_a(spdm_context, spdm_response, spdm_response_size);
157 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
158 0 : libspdm_reset_message_a(spdm_context);
159 0 : goto receive_done;
160 : }
161 :
162 6 : result = libspdm_negotiate_connection_version (
163 : &common_version,
164 6 : spdm_context->local_context.version.spdm_version,
165 6 : spdm_context->local_context.version.spdm_version_count,
166 6 : spdm_response->version_number_entry,
167 6 : spdm_response->version_number_entry_count);
168 6 : if (result == false) {
169 1 : libspdm_reset_message_a(spdm_context);
170 1 : status = LIBSPDM_STATUS_NEGOTIATION_FAIL;
171 1 : goto receive_done;
172 : }
173 :
174 5 : libspdm_copy_mem(&(spdm_context->connection_info.version),
175 : sizeof(spdm_context->connection_info.version),
176 : &(common_version), sizeof(spdm_version_number_t));
177 :
178 5 : if (version_number_entry_count != NULL && version_number_entry != NULL) {
179 0 : if (*version_number_entry_count < spdm_response->version_number_entry_count) {
180 0 : *version_number_entry_count = spdm_response->version_number_entry_count;
181 0 : libspdm_reset_message_a(spdm_context);
182 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
183 0 : goto receive_done;
184 : } else {
185 0 : *version_number_entry_count = spdm_response->version_number_entry_count;
186 0 : libspdm_copy_mem(version_number_entry,
187 0 : spdm_response->version_number_entry_count *
188 : sizeof(spdm_version_number_t),
189 0 : spdm_response->version_number_entry,
190 0 : spdm_response->version_number_entry_count *
191 : sizeof(spdm_version_number_t));
192 0 : libspdm_version_number_sort (version_number_entry, *version_number_entry_count);
193 : }
194 : }
195 :
196 : /* -=[Update State Phase]=- */
197 5 : spdm_context->connection_info.connection_state = LIBSPDM_CONNECTION_STATE_AFTER_VERSION;
198 5 : status = LIBSPDM_STATUS_SUCCESS;
199 :
200 : /* -=[Log Message Phase]=- */
201 : #if LIBSPDM_ENABLE_MSG_LOG
202 5 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
203 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
204 :
205 : /*Set the role of device*/
206 5 : spdm_context->local_context.is_requester = true;
207 :
208 36 : receive_done:
209 36 : libspdm_release_receiver_buffer (spdm_context);
210 36 : return status;
211 : }
212 :
213 38 : libspdm_return_t libspdm_get_version(libspdm_context_t *spdm_context,
214 : uint8_t *version_number_entry_count,
215 : spdm_version_number_t *version_number_entry)
216 : {
217 : size_t retry;
218 : uint64_t retry_delay_time;
219 : libspdm_return_t status;
220 :
221 38 : spdm_context->crypto_request = false;
222 38 : retry = spdm_context->retry_times;
223 38 : retry_delay_time = spdm_context->retry_delay_time;
224 : do {
225 39 : status = libspdm_try_get_version(spdm_context,
226 : version_number_entry_count, version_number_entry);
227 39 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
228 37 : return status;
229 : }
230 :
231 2 : libspdm_sleep(retry_delay_time);
232 2 : } while (retry-- != 0);
233 :
234 1 : return status;
235 : }
|