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