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_SET_CERT_CAP
10 : /**
11 : * This function sends SET_CERTIFICATE
12 : * to set certificate from the device.
13 : *
14 : * @param context A pointer to the SPDM context.
15 : * @param session_id Indicates if it is a secured message protected via SPDM session.
16 : * If session_id is NULL, it is a normal message.
17 : * If session_id is NOT NULL, it is a secured message.
18 : * @param slot_id The number of slot for the certificate chain.
19 : * @param cert_chain The pointer for the certificate chain to set.
20 : * The cert chain is a full SPDM certificate chain, including Length and Root Cert Hash.
21 : * @param cert_chain_size The size of the certificate chain to set.
22 : * @param request_attribute Set certificate request attributes. This field is only used for SPDM 1.3 and above.
23 : * And the bit[0~3] of request_attribute must be 0.
24 : * @param key_pair_id The value of this field shall be the unique key pair number identifying the desired
25 : * asymmetric key pair to associate with SlotID .
26 : *
27 : * @retval RETURN_SUCCESS The measurement is got successfully.
28 : * @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device.
29 : * @retval RETURN_SECURITY_VIOLATION Any verification fails.
30 : **/
31 8 : static libspdm_return_t libspdm_try_set_certificate(libspdm_context_t *spdm_context,
32 : const uint32_t *session_id, uint8_t slot_id,
33 : void *cert_chain, size_t cert_chain_size,
34 : uint8_t request_attribute,
35 : uint8_t key_pair_id)
36 : {
37 : libspdm_return_t status;
38 : spdm_set_certificate_request_t *spdm_request;
39 : size_t spdm_request_size;
40 : spdm_set_certificate_response_t *spdm_response;
41 : size_t spdm_response_size;
42 : size_t transport_header_size;
43 : uint8_t *message;
44 : size_t message_size;
45 : libspdm_session_info_t *session_info;
46 : libspdm_session_state_t session_state;
47 :
48 8 : LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
49 :
50 8 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_12) {
51 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
52 : }
53 8 : if (libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_13) {
54 5 : if ((cert_chain == NULL) || (cert_chain_size == 0)) {
55 1 : return LIBSPDM_STATUS_INVALID_PARAMETER;
56 : }
57 : }
58 7 : if (libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_13) {
59 3 : const uint8_t set_cert_model =
60 3 : (request_attribute & SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_MASK) >>
61 : SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_OFFSET;
62 :
63 : /* Bit[0~3] of request_attribute must be 0 since this value is provided by the slot_id
64 : * parameter. */
65 3 : if ((request_attribute & SPDM_SET_CERTIFICATE_REQUEST_SLOT_ID_MASK) != 0) {
66 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
67 : }
68 :
69 : /* SET_CERT_CAP for a 1.2 Responder is not checked because it was not defined
70 : * in SPDM 1.2.0. */
71 3 : if (!libspdm_is_capabilities_flag_supported(
72 : spdm_context, true, 0,
73 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP)) {
74 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
75 : }
76 3 : if (spdm_context->connection_info.multi_key_conn_rsp) {
77 2 : if (key_pair_id == 0) {
78 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
79 : }
80 2 : if ((request_attribute & SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_ERASE) == 0) {
81 2 : if ((set_cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) ||
82 : (set_cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
83 1 : return LIBSPDM_STATUS_INVALID_PARAMETER;
84 : }
85 : }
86 : } else {
87 1 : if ((key_pair_id != 0) || (set_cert_model != 0)) {
88 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
89 : }
90 : }
91 : }
92 :
93 6 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
94 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
95 : }
96 :
97 6 : if (session_id != NULL) {
98 1 : session_info = libspdm_get_session_info_via_session_id(
99 : spdm_context, *session_id);
100 1 : if (session_info == NULL) {
101 0 : LIBSPDM_ASSERT(false);
102 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
103 : }
104 1 : session_state = libspdm_secured_message_get_session_state(
105 : session_info->secured_message_context);
106 1 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
107 0 : return LIBSPDM_STATUS_INVALID_STATE_LOCAL;
108 : }
109 : }
110 :
111 6 : transport_header_size = spdm_context->local_context.capability.transport_header_size;
112 6 : status = libspdm_acquire_sender_buffer (spdm_context, &message_size, (void **)&message);
113 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
114 0 : return status;
115 : }
116 6 : LIBSPDM_ASSERT (message_size >= transport_header_size +
117 : spdm_context->local_context.capability.transport_tail_size);
118 6 : spdm_request = (void *)(message + transport_header_size);
119 6 : spdm_request_size = message_size - transport_header_size -
120 6 : spdm_context->local_context.capability.transport_tail_size;
121 :
122 6 : LIBSPDM_ASSERT(spdm_request_size >= sizeof(spdm_set_certificate_request_t));
123 6 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
124 6 : spdm_request->header.request_response_code = SPDM_SET_CERTIFICATE;
125 6 : spdm_request->header.param1 = slot_id & SPDM_SET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
126 6 : spdm_request->header.param2 = 0;
127 :
128 6 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
129 2 : if ((request_attribute & SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_ERASE) != 0) {
130 : /*the CertChain field shall be absent*/
131 1 : cert_chain_size = 0;
132 : /*the value of SetCertModel shall be zero*/
133 1 : spdm_request->header.param1 &= ~SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_CERT_MODEL_MASK;
134 : /*set Erase bit */
135 1 : spdm_request->header.param1 |= SPDM_SET_CERTIFICATE_REQUEST_ATTRIBUTES_ERASE;
136 : } else {
137 1 : spdm_request->header.param1 |= request_attribute;
138 : }
139 :
140 2 : if (spdm_context->connection_info.multi_key_conn_rsp) {
141 1 : spdm_request->header.param2 = key_pair_id;
142 : }
143 : }
144 :
145 6 : if ((libspdm_get_connection_version (spdm_context) < SPDM_MESSAGE_VERSION_13) ||
146 : (cert_chain_size != 0)) {
147 5 : if (cert_chain == NULL) {
148 0 : libspdm_release_sender_buffer (spdm_context);
149 0 : return LIBSPDM_STATUS_INVALID_PARAMETER;
150 : }
151 :
152 5 : LIBSPDM_ASSERT(spdm_request_size >=
153 : sizeof(spdm_set_certificate_request_t) + cert_chain_size);
154 5 : libspdm_copy_mem(spdm_request + 1,
155 : spdm_request_size - sizeof(spdm_set_certificate_request_t),
156 : (uint8_t *)cert_chain, cert_chain_size);
157 : }
158 :
159 6 : spdm_request_size = sizeof(spdm_set_certificate_request_t) + cert_chain_size;
160 :
161 6 : status = libspdm_send_spdm_request(spdm_context, session_id, spdm_request_size, spdm_request);
162 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
163 1 : libspdm_release_sender_buffer (spdm_context);
164 1 : return status;
165 : }
166 5 : libspdm_release_sender_buffer (spdm_context);
167 5 : spdm_request = (void *)spdm_context->last_spdm_request;
168 :
169 : /* receive */
170 5 : status = libspdm_acquire_receiver_buffer (spdm_context, &message_size, (void **)&message);
171 5 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
172 0 : return status;
173 : }
174 5 : LIBSPDM_ASSERT (message_size >= transport_header_size);
175 5 : spdm_response = (void *)(message);
176 5 : spdm_response_size = message_size;
177 :
178 5 : status = libspdm_receive_spdm_response(spdm_context, session_id,
179 : &spdm_response_size, (void **)&spdm_response);
180 :
181 5 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
182 0 : goto receive_done;
183 : }
184 5 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
185 0 : status = LIBSPDM_STATUS_INVALID_MSG_SIZE;
186 0 : goto receive_done;
187 : }
188 5 : if (spdm_response->header.spdm_version != spdm_request->header.spdm_version) {
189 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
190 0 : goto receive_done;
191 : }
192 5 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
193 1 : status = libspdm_handle_error_response_main(
194 : spdm_context, NULL,
195 : &spdm_response_size,
196 : (void **)&spdm_response, SPDM_SET_CERTIFICATE, SPDM_SET_CERTIFICATE_RSP);
197 1 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
198 1 : goto receive_done;
199 : }
200 4 : } else if (spdm_response->header.request_response_code != SPDM_SET_CERTIFICATE_RSP) {
201 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
202 0 : goto receive_done;
203 : }
204 4 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
205 0 : status = LIBSPDM_STATUS_INVALID_MSG_FIELD;
206 0 : goto receive_done;
207 : }
208 :
209 : /* -=[Log Message Phase]=- */
210 : #if LIBSPDM_ENABLE_MSG_LOG
211 4 : libspdm_append_msg_log(spdm_context, spdm_response, spdm_response_size);
212 : #endif /* LIBSPDM_ENABLE_MSG_LOG */
213 :
214 4 : status = LIBSPDM_STATUS_SUCCESS;
215 :
216 5 : receive_done:
217 5 : libspdm_release_receiver_buffer (spdm_context);
218 5 : return status;
219 : }
220 :
221 5 : libspdm_return_t libspdm_set_certificate(void *spdm_context,
222 : const uint32_t *session_id, uint8_t slot_id,
223 : void *cert_chain, size_t cert_chain_size)
224 : {
225 : libspdm_context_t *context;
226 : size_t retry;
227 : uint64_t retry_delay_time;
228 : libspdm_return_t status;
229 :
230 5 : context = spdm_context;
231 5 : context->crypto_request = true;
232 5 : retry = context->retry_times;
233 5 : retry_delay_time = context->retry_delay_time;
234 : do {
235 5 : status = libspdm_try_set_certificate(context, session_id, slot_id,
236 : cert_chain, cert_chain_size, 0, 0);
237 5 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
238 5 : return status;
239 : }
240 :
241 0 : libspdm_sleep(retry_delay_time);
242 0 : } while (retry-- != 0);
243 :
244 0 : return status;
245 : }
246 :
247 3 : libspdm_return_t libspdm_set_certificate_ex(void *spdm_context,
248 : const uint32_t *session_id, uint8_t slot_id,
249 : void *cert_chain, size_t cert_chain_size,
250 : uint8_t request_attribute,
251 : uint8_t key_pair_id)
252 : {
253 : libspdm_context_t *context;
254 : size_t retry;
255 : uint64_t retry_delay_time;
256 : libspdm_return_t status;
257 :
258 3 : context = spdm_context;
259 3 : context->crypto_request = true;
260 3 : retry = context->retry_times;
261 3 : retry_delay_time = context->retry_delay_time;
262 : do {
263 3 : status = libspdm_try_set_certificate(context, session_id, slot_id,
264 : cert_chain, cert_chain_size,
265 : request_attribute, key_pair_id);
266 3 : if (status != LIBSPDM_STATUS_BUSY_PEER) {
267 3 : return status;
268 : }
269 :
270 0 : libspdm_sleep(retry_delay_time);
271 0 : } while (retry-- != 0);
272 :
273 0 : return status;
274 : }
275 :
276 : #endif /*LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP*/
|