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 : : #include "internal/libspdm_responder_lib.h"
7 : :
8 : : #if LIBSPDM_ENABLE_CAPABILITY_CERT_CAP
9 : :
10 : 1720 : libspdm_return_t libspdm_get_response_certificate(libspdm_context_t *spdm_context,
11 : : size_t request_size,
12 : : const void *request,
13 : : size_t *response_size,
14 : : void *response)
15 : : {
16 : : const spdm_get_certificate_large_request_t *spdm_request;
17 : : spdm_certificate_large_response_t *spdm_response;
18 : : uint32_t offset;
19 : : uint32_t length;
20 : : uint32_t remainder_length;
21 : : uint8_t slot_id;
22 : : libspdm_return_t status;
23 : : size_t response_capacity;
24 : : libspdm_session_info_t *session_info;
25 : : libspdm_session_state_t session_state;
26 : : bool use_large_cert_chain;
27 : : bool slot_size_requested;
28 : : uint32_t req_msg_header_size;
29 : : uint32_t rsp_msg_header_size;
30 : : size_t cert_chain_size;
31 : : uint32_t max_cert_chain_block_size;
32 : :
33 : 1720 : spdm_request = request;
34 : :
35 : : /* -=[Check Parameters Phase]=- */
36 [ - + ]: 1720 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_GET_CERTIFICATE);
37 : :
38 [ - + ]: 1720 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
39 : 0 : return libspdm_generate_error_response(spdm_context,
40 : : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
41 : : response_size, response);
42 : : }
43 [ + + ]: 1720 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
44 : 4 : return libspdm_responder_handle_response_state(
45 : : spdm_context,
46 : 4 : spdm_request->header.request_response_code,
47 : : response_size, response);
48 : : }
49 [ + + ]: 1716 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
50 : 2 : return libspdm_generate_error_response(spdm_context,
51 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
52 : : 0, response_size, response);
53 : : }
54 : 1714 : session_info = NULL;
55 [ + + ]: 1714 : if (spdm_context->last_spdm_request_session_id_valid) {
56 : 7 : session_info = libspdm_get_session_info_via_session_id(
57 : : spdm_context,
58 : : spdm_context->last_spdm_request_session_id);
59 [ - + ]: 7 : if (session_info == NULL) {
60 : 0 : return libspdm_generate_error_response(
61 : : spdm_context,
62 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
63 : : response_size, response);
64 : : }
65 : 7 : session_state = libspdm_secured_message_get_session_state(
66 : : session_info->secured_message_context);
67 [ - + ]: 7 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
68 : 0 : return libspdm_generate_error_response(
69 : : spdm_context,
70 : : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
71 : : response_size, response);
72 : : }
73 : : }
74 [ - + ]: 1714 : if (!libspdm_is_capabilities_flag_supported(
75 : : spdm_context, false, 0,
76 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
77 : 0 : return libspdm_generate_error_response(
78 : : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
79 : : SPDM_GET_CERTIFICATE, response_size, response);
80 : : }
81 : :
82 [ - + ]: 1714 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
83 [ # # ]: 0 : ((spdm_request->header.param1 & SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN) != 0)) {
84 [ # # ]: 0 : if (!libspdm_is_capabilities_flag_supported(
85 : : spdm_context, false, 0,
86 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
87 : 0 : return libspdm_generate_error_response(
88 : : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
89 : : SPDM_GET_CERTIFICATE, response_size, response);
90 : : }
91 : 0 : use_large_cert_chain = true;
92 : : } else {
93 : 1714 : use_large_cert_chain = false;
94 : : }
95 : :
96 [ - + ]: 1714 : if (use_large_cert_chain) {
97 : 0 : req_msg_header_size = sizeof(spdm_get_certificate_large_request_t);
98 : 0 : rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
99 : : } else {
100 : 1714 : req_msg_header_size = sizeof(spdm_get_certificate_request_t);
101 : 1714 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
102 : : }
103 : :
104 [ - + ]: 1714 : if (request_size < req_msg_header_size) {
105 : 0 : return libspdm_generate_error_response(spdm_context,
106 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
107 : : response_size, response);
108 : : }
109 : :
110 : 1714 : slot_id = spdm_request->header.param1 & SPDM_GET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
111 : :
112 [ + + ]: 1714 : if (slot_id >= SPDM_MAX_SLOT_COUNT) {
113 : 1 : return libspdm_generate_error_response(spdm_context,
114 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
115 : : response_size, response);
116 : : }
117 : :
118 [ + + ]: 1713 : if ((spdm_context->local_context.cert_slot_reset_mask & (1 << slot_id)) != 0) {
119 [ - + ]: 1 : LIBSPDM_ASSERT(spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12);
120 : 1 : return libspdm_generate_error_response(spdm_context,
121 : : SPDM_ERROR_CODE_RESET_REQUIRED, 0,
122 : : response_size, response);
123 : : }
124 : :
125 : : /* The SlotSizeRequested attribute is only defined for SPDM 1.3 and later; in earlier
126 : : * versions the param2 bit is reserved and must be ignored. */
127 [ + + ]: 1712 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
128 : 2 : slot_size_requested =
129 : 2 : ((spdm_request->header.param2 &
130 : : SPDM_GET_CERTIFICATE_REQUEST_ATTRIBUTES_SLOT_SIZE_REQUESTED) != 0);
131 : : } else {
132 : 1710 : slot_size_requested = false;
133 : : }
134 : :
135 [ + + ]: 1712 : if (!slot_size_requested &&
136 [ - + ]: 1710 : (spdm_context->local_context.local_cert_chain_provision[slot_id] == NULL)) {
137 : 0 : return libspdm_generate_error_response(
138 : : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
139 : : 0, response_size, response);
140 : : }
141 : :
142 [ + + ]: 1712 : if (spdm_context->local_context.local_cert_chain_provision[slot_id] == NULL) {
143 : 1 : cert_chain_size = 0;
144 : : } else {
145 : 1711 : cert_chain_size = spdm_context->local_context.local_cert_chain_provision_size[slot_id];
146 : : }
147 : :
148 [ - + ]: 1712 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
149 [ # # # # ]: 0 : (!use_large_cert_chain) && (cert_chain_size > SPDM_MAX_CERTIFICATE_CHAIN_SIZE)) {
150 : 0 : return libspdm_generate_extended_error_response(
151 : : spdm_context, SPDM_ERROR_CODE_DATA_TOO_LARGE, 0,
152 : : sizeof(spdm_error_data_cert_chain_too_large_t),
153 : : (const uint8_t *)&cert_chain_size,
154 : : response_size, response);
155 : : }
156 : :
157 [ - + ]: 1712 : if (use_large_cert_chain) {
158 : 0 : offset = spdm_request->large_offset;
159 : 0 : length = spdm_request->large_length;
160 : : } else {
161 : 1712 : offset = spdm_request->offset;
162 : 1712 : length = spdm_request->length;
163 : : }
164 : :
165 [ + + ]: 1712 : if (slot_size_requested) {
166 : 2 : offset = 0;
167 : 2 : length = 0;
168 : : }
169 : :
170 [ + + + + ]: 1712 : if (!slot_size_requested && (offset >= cert_chain_size)) {
171 : 126 : return libspdm_generate_error_response(spdm_context,
172 : : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
173 : : response_size, response);
174 : : }
175 : :
176 [ + + ]: 1586 : if (!libspdm_is_capabilities_flag_supported(spdm_context, false,
177 : : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
178 : : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
179 : 1582 : max_cert_chain_block_size = (uint32_t) (*response_size - rsp_msg_header_size);
180 [ + - ]: 1582 : if (!use_large_cert_chain){
181 : 1582 : max_cert_chain_block_size = LIBSPDM_MIN(max_cert_chain_block_size, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
182 : : }
183 : :
184 [ + + ]: 1582 : if (length > max_cert_chain_block_size) {
185 : 67 : length = max_cert_chain_block_size;
186 : : }
187 : : }
188 : :
189 [ + + ]: 1586 : if (((uint64_t)offset + length) > cert_chain_size) {
190 : 21 : length = (uint32_t)(cert_chain_size - offset);
191 : : }
192 : 1586 : remainder_length = (uint32_t)(cert_chain_size - (length + offset));
193 : :
194 : 1586 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
195 : 1586 : spdm_request->header.request_response_code);
196 : :
197 [ - + ]: 1586 : LIBSPDM_ASSERT(*response_size >= rsp_msg_header_size + length);
198 : 1586 : response_capacity = *response_size;
199 : 1586 : *response_size = rsp_msg_header_size + length;
200 : 1586 : libspdm_zero_mem(response, *response_size);
201 : 1586 : spdm_response = response;
202 : :
203 : 1586 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
204 : 1586 : spdm_response->header.request_response_code = SPDM_CERTIFICATE;
205 : 1586 : spdm_response->header.param1 = slot_id;
206 : 1586 : spdm_response->header.param2 = 0;
207 [ + + ]: 1586 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
208 [ - + ]: 2 : spdm_context->connection_info.multi_key_conn_rsp) {
209 : 0 : spdm_response->header.param2 = spdm_context->local_context.local_cert_info[slot_id];
210 : : }
211 [ - + ]: 1586 : if (use_large_cert_chain) {
212 : 0 : spdm_response->header.param1 |= SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN;
213 : : }
214 : :
215 : : #if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP
216 [ + + ]: 1586 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
217 [ + - ]: 2 : (spdm_request->header.param2 & SPDM_GET_CERTIFICATE_REQUEST_ATTRIBUTES_SLOT_SIZE_REQUESTED)) {
218 : 2 : remainder_length = libspdm_get_cert_chain_slot_storage_size(spdm_context, slot_id);
219 : : }
220 : : #endif /* LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP */
221 : :
222 [ - + ]: 1586 : if (use_large_cert_chain) {
223 : 0 : spdm_response->portion_length = 0;
224 : 0 : spdm_response->remainder_length = 0;
225 : 0 : spdm_response->large_portion_length = length;
226 : 0 : spdm_response->large_remainder_length = remainder_length;
227 : : } else {
228 : 1586 : spdm_response->portion_length = (uint16_t)length;
229 : 1586 : spdm_response->remainder_length = (uint16_t)remainder_length;
230 : : }
231 : :
232 : : /* A SlotSizeRequested query carries no certificate data (length == 0), and the slot may be
233 : : * empty (provision == NULL), so skip the copy to avoid dereferencing a NULL source. */
234 [ + + ]: 1586 : if (length != 0) {
235 : 1583 : libspdm_copy_mem((uint8_t *)spdm_response + rsp_msg_header_size,
236 : : response_capacity - rsp_msg_header_size,
237 : : (const uint8_t *)spdm_context->local_context
238 : 1583 : .local_cert_chain_provision[slot_id] + offset, length);
239 : : }
240 : :
241 [ + + ]: 1586 : if (session_info == NULL) {
242 : : /* Log to transcript. */
243 : 1581 : const size_t spdm_request_size = req_msg_header_size;
244 : :
245 : 1581 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
246 [ - + ]: 1581 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
247 : 0 : return libspdm_generate_error_response(spdm_context,
248 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
249 : : response_size, response);
250 : : }
251 : :
252 : 1581 : status = libspdm_append_message_b(spdm_context, spdm_response, *response_size);
253 [ - + ]: 1581 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
254 : 0 : return libspdm_generate_error_response(spdm_context,
255 : : SPDM_ERROR_CODE_UNSPECIFIED, 0,
256 : : response_size, response);
257 : : }
258 : : }
259 : :
260 [ + + ]: 1586 : if (spdm_context->connection_info.connection_state <
261 : : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE) {
262 : 16 : libspdm_set_connection_state(spdm_context, LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE);
263 : : }
264 : :
265 : 1586 : return LIBSPDM_STATUS_SUCCESS;
266 : : }
267 : :
268 : : #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
|