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