Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-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_CSR_CAP
10 :
11 : /**
12 : * This function sends GET_CSR
13 : * to get csr from the device.
14 : *
15 : * @param[in] context A pointer to the SPDM context.
16 : * @param[in] session_id Indicates if it is a secured message protected via SPDM session.
17 : * If session_id is NULL, it is a normal message.
18 : * If session_id is NOT NULL, it is a secured message.
19 : * @param[in] requester_info requester info to gen CSR
20 : * @param[in] requester_info_length The len of requester info
21 : * @param[in] opaque_data opaque data
22 : * @param[in] opaque_data_length The len of opaque data
23 : * @param[out] csr address to store CSR.
24 : * @param[in, out] csr_len on input, *csr_len indicates the max csr buffer size.
25 : * on output, *csr_len indicates the actual csr buffer size.
26 : * @param[in] request_attribute Set certificate request attributes. This field is only used for SPDM 1.3 and above.
27 : * @param[in] key_pair_id The value of this field shall be the unique key pair number identifying the desired
28 : * asymmetric key pair to associate with SlotID .
29 : * @param[out] available_csr_tracking_tag available CSRTrackingTag when the Responder sends a ResetRequired error message
30 : **/
31 8 : static libspdm_return_t libspdm_try_get_csr(libspdm_context_t *spdm_context,
32 : const uint32_t *session_id,
33 : void *requester_info, uint16_t requester_info_length,
34 : void *opaque_data, uint16_t opaque_data_length,
35 : void *csr, size_t *csr_len,
36 : uint8_t request_attribute,
37 : uint8_t key_pair_id,
38 : uint8_t *available_csr_tracking_tag)
39 : {
40 : libspdm_return_t status;
41 : libspdm_return_t warning;
42 : spdm_get_csr_request_t *spdm_request;
43 : size_t spdm_request_size;
44 : spdm_csr_response_t *spdm_response;
45 : size_t spdm_response_size;
46 : size_t transport_header_size;
47 : uint8_t *message;
48 : size_t message_size;
49 : libspdm_session_info_t *session_info;
50 : libspdm_session_state_t session_state;
51 :
52 8 : warning = LIBSPDM_STATUS_SUCCESS;
53 :
54 8 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
55 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
56 : }
57 8 : if (libspdm_get_connection_version(spdm_context) == SPDM_MESSAGE_VERSION_12) {
58 5 : if ((key_pair_id != 0) || (request_attribute != 0)) {
59 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
60 : }
61 : }
62 :
63 8 : if (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_13) {
64 3 : const uint8_t csr_cert_model = request_attribute &
65 : SPDM_GET_CSR_REQUEST_ATTRIBUTES_CERT_MODEL_MASK;
66 :
67 : /* CSR_CAP for a 1.2 Responder is not checked because it was not defined in SPDM 1.2.0. */
68 3 : if (!libspdm_is_capabilities_flag_supported(
69 : spdm_context, true, 0,
70 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP)) {
71 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
72 : }
73 3 : if (spdm_context->connection_info.multi_key_conn_rsp) {
74 1 : if (key_pair_id == 0) {
75 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
76 : }
77 1 : if ((csr_cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) ||
78 : (csr_cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
79 1 : return LIBSPDM_STATUS_INVALID_PARAMETER;
80 : }
81 : } else {
82 2 : if ((key_pair_id != 0) || (csr_cert_model != 0)) {
83 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
84 : }
85 : }
86 : }
87 :
88 7 : LIBSPDM_ASSERT(opaque_data_length < SPDM_MAX_OPAQUE_DATA_SIZE);
89 :
90 7 : if (spdm_context->connection_info.connection_state <
91 : LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
92 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
93 : }
94 :
95 7 : if (session_id != NULL) {
96 0 : session_info = libspdm_get_session_info_via_session_id(
97 : spdm_context, *session_id);
98 0 : if (session_info == NULL) {
99 0 : LIBSPDM_ASSERT(false);
100 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
101 : }
102 0 : session_state = libspdm_secured_message_get_session_state(
103 : session_info->secured_message_context);
104 0 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
105 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
106 : }
107 : }
108 :
109 7 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
110 7 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
111 7 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
112 0 : return status;
113 : }
114 7 : LIBSPDM_ASSERT (message_size >= transport_header_size +
115 : spdm_context->local_context.capability.transport_tail_size);
116 7 : spdm_request = (void *)(message + transport_header_size);
117 7 : spdm_request_size = message_size - transport_header_size -
118 7 : spdm_context->local_context.capability.transport_tail_size;
119 :
120 7 : LIBSPDM_ASSERT (spdm_request_size >= sizeof(spdm_get_csr_request_t) + opaque_data_length
121 : + requester_info_length);
122 7 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
123 7 : spdm_request->header.request_response_code = SPDM_GET_CSR;
124 7 : spdm_request->header.param1 = key_pair_id;
125 7 : spdm_request->header.param2 = request_attribute;
126 :
127 7 : spdm_request->opaque_data_length = opaque_data_length;
128 7 : spdm_request->requester_info_length = requester_info_length;
129 :
130 7 : if (requester_info_length != 0) {
131 2 : libspdm_copy_mem(spdm_request + 1,
132 : spdm_request_size - sizeof(spdm_get_csr_request_t),
133 : (uint8_t *)requester_info, requester_info_length);
134 : }
135 :
136 7 : if (((spdm_context->connection_info.algorithm.other_params_support &
137 4 : SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_MASK) == SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_NONE) &&
138 : (opaque_data_length != 0)) {
139 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Overriding opaque_data_length to 0 since there is "
140 : "no negotiated opaque data format.\n"));
141 0 : opaque_data_length = 0;
142 0 : warning = LIBSPDM_STATUS_OVERRIDDEN_PARAMETER;
143 : }
144 :
145 7 : if (opaque_data_length != 0) {
146 2 : libspdm_copy_mem((uint8_t *)(spdm_request + 1) + requester_info_length,
147 2 : spdm_request_size - sizeof(spdm_get_csr_request_t) - requester_info_length,
148 : (uint8_t *)opaque_data, opaque_data_length);
149 : }
150 :
151 7 : spdm_request_size = sizeof(spdm_get_csr_request_t) + opaque_data_length
152 7 : + requester_info_length;
153 :
154 7 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
155 7 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
156 1 : libspdm_release_sender_buffer (spdm_context);
157 1 : return status;
158 : }
159 6 : libspdm_release_sender_buffer (spdm_context);
160 6 : spdm_request = (void *)spdm_context->last_spdm_request;
161 :
162 : /* receive */
163 6 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
164 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
165 0 : return status;
166 : }
167 6 : LIBSPDM_ASSERT (message_size >= transport_header_size);
168 6 : spdm_response = (void *)(message);
169 6 : spdm_response_size = message_size;
170 :
171 6 : status = libspdm_receive_spdm_response(spdm_context, session_id,
172 : &spdm_response_size, (void **)&spdm_response);
173 :
174 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
175 0 : goto receive_done;
176 : }
177 6 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
178 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
179 0 : goto receive_done;
180 : }
181 6 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
182 6 : if ((spdm_response->header.param1 == SPDM_ERROR_CODE_RESET_REQUIRED) &&
183 5 : (libspdm_get_connection_version(spdm_context) >= SPDM_MESSAGE_VERSION_13) &&
184 : (available_csr_tracking_tag != NULL)) {
185 1 : *available_csr_tracking_tag = spdm_response->header.param2;
186 : }
187 :
188 3 : status = libspdm_handle_error_response_main(
189 : spdm_context, session_id,
190 : &spdm_response_size,
191 : (void **)&spdm_response, SPDM_GET_CSR, SPDM_CSR);
192 3 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
193 3 : goto receive_done;
194 : }
195 3 : } else if (spdm_response->header.request_response_code != SPDM_CSR) {
196 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
197 0 : goto receive_done;
198 : }
199 3 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
200 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
201 0 : goto receive_done;
202 : }
203 :
204 3 : if (spdm_response_size < sizeof(spdm_csr_response_t)) {
205 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
206 0 : goto receive_done;
207 : }
208 3 : if (spdm_response->csr_length == 0) {
209 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
210 0 : goto receive_done;
211 : }
212 :
213 3 : if (spdm_response_size < sizeof(spdm_csr_response_t) + spdm_response->csr_length) {
214 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
215 0 : goto receive_done;
216 : }
217 3 : if (*csr_len < spdm_response->csr_length) {
218 0 : *csr_len = spdm_response->csr_length;
219 0 : status = LIBSPDM_STATUS_BUFFER_TOO_SMALL;
220 0 : goto receive_done;
221 : }
222 :
223 3 : libspdm_copy_mem(csr, *csr_len, spdm_response + 1, spdm_response->csr_length);
224 3 : *csr_len = spdm_response->csr_length;
225 :
226 3 : status = LIBSPDM_STATUS_SUCCESS;
227 :
228 6 : receive_done:
229 6 : libspdm_release_receiver_buffer (spdm_context);
230 :
231 6 : if (LIBSPDM_STATUS_IS_SUCCESS(status) && LIBSPDM_STATUS_IS_WARNING(warning)) {
232 0 : status = warning;
233 : }
234 6 : return status;
235 : }
236 :
237 6 : libspdm_return_t libspdm_get_csr(void * spdm_context,
238 : const uint32_t *session_id,
239 : void * requester_info, uint16_t requester_info_length,
240 : void * opaque_data, uint16_t opaque_data_length,
241 : void *csr, size_t *csr_len)
242 : {
243 : libspdm_context_t *context;
244 : size_t retry;
245 : uint64_t retry_delay_time;
246 : libspdm_return_t status;
247 :
248 6 : context = spdm_context;
249 6 : context->crypto_request = true;
250 6 : retry = context->retry_times;
251 6 : retry_delay_time = context->retry_delay_time;
252 : do {
253 6 : status = libspdm_try_get_csr(context, session_id,
254 : requester_info, requester_info_length,
255 : opaque_data, opaque_data_length,
256 : csr, csr_len,
257 : 0, 0, NULL);
258 6 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
259 6 : return status;
260 : }
261 :
262 0 : libspdm_sleep(retry_delay_time);
263 0 : } while (retry-- != 0);
264 :
265 0 : return status;
266 : }
267 :
268 : #if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX
269 2 : libspdm_return_t libspdm_get_csr_ex(void * spdm_context,
270 : const uint32_t *session_id,
271 : void * requester_info, uint16_t requester_info_length,
272 : void * opaque_data, uint16_t opaque_data_length,
273 : void *csr, size_t *csr_len,
274 : uint8_t request_attribute,
275 : uint8_t key_pair_id,
276 : uint8_t *available_csr_tracking_tag
277 : )
278 : {
279 : libspdm_context_t *context;
280 : size_t retry;
281 : uint64_t retry_delay_time;
282 : libspdm_return_t status;
283 :
284 2 : context = spdm_context;
285 2 : context->crypto_request = true;
286 2 : retry = context->retry_times;
287 2 : retry_delay_time = context->retry_delay_time;
288 : do {
289 2 : status = libspdm_try_get_csr(context, session_id,
290 : requester_info, requester_info_length,
291 : opaque_data, opaque_data_length,
292 : csr, csr_len,
293 : request_attribute, key_pair_id,
294 : available_csr_tracking_tag);
295 2 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
296 2 : return status;
297 : }
298 :
299 0 : libspdm_sleep(retry_delay_time);
300 0 : } while (retry-- != 0);
301 :
302 0 : return status;
303 : }
304 : #endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP_EX*/
305 :
306 : #endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP*/
|