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 1715 : 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 1715 : spdm_request = request;
34 :
35 : /* -=[Check Parameters Phase]=- */
36 1715 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_GET_CERTIFICATE);
37 :
38 1715 : 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 1715 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
44 3 : return libspdm_responder_handle_response_state(
45 : spdm_context,
46 3 : spdm_request->header.request_response_code,
47 : response_size, response);
48 : }
49 1712 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
50 1 : return libspdm_generate_error_response(spdm_context,
51 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
52 : 0, response_size, response);
53 : }
54 1711 : session_info = NULL;
55 1711 : 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 1711 : 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 1711 : 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 1711 : use_large_cert_chain = false;
94 : }
95 :
96 1711 : 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 1711 : req_msg_header_size = sizeof(spdm_get_certificate_request_t);
101 1711 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
102 : }
103 :
104 1711 : 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 1711 : slot_id = spdm_request->header.param1 & SPDM_GET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
111 :
112 1711 : 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 1710 : 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 1709 : 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 1707 : slot_size_requested = false;
133 : }
134 :
135 1709 : if (!slot_size_requested &&
136 1707 : (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 1709 : if (spdm_context->local_context.local_cert_chain_provision[slot_id] == NULL) {
143 1 : cert_chain_size = 0;
144 : } else {
145 1708 : cert_chain_size = spdm_context->local_context.local_cert_chain_provision_size[slot_id];
146 : }
147 :
148 1709 : 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 1709 : if (use_large_cert_chain) {
158 0 : offset = spdm_request->large_offset;
159 0 : length = spdm_request->large_length;
160 : } else {
161 1709 : offset = spdm_request->offset;
162 1709 : length = spdm_request->length;
163 : }
164 :
165 1709 : if (slot_size_requested) {
166 2 : offset = 0;
167 2 : length = 0;
168 : }
169 :
170 1709 : 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 1583 : 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 1579 : max_cert_chain_block_size = (uint32_t) (*response_size - rsp_msg_header_size);
180 1579 : if (!use_large_cert_chain){
181 1579 : max_cert_chain_block_size = LIBSPDM_MIN(max_cert_chain_block_size, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
182 : }
183 :
184 1579 : if (length > max_cert_chain_block_size) {
185 67 : length = max_cert_chain_block_size;
186 : }
187 : }
188 :
189 1583 : if (((uint64_t)offset + length) > cert_chain_size) {
190 18 : length = (uint32_t)(cert_chain_size - offset);
191 : }
192 1583 : remainder_length = (uint32_t)(cert_chain_size - (length + offset));
193 :
194 1583 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
195 1583 : spdm_request->header.request_response_code);
196 :
197 1583 : LIBSPDM_ASSERT(*response_size >= rsp_msg_header_size + length);
198 1583 : response_capacity = *response_size;
199 1583 : *response_size = rsp_msg_header_size + length;
200 1583 : libspdm_zero_mem(response, *response_size);
201 1583 : spdm_response = response;
202 :
203 1583 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
204 1583 : spdm_response->header.request_response_code = SPDM_CERTIFICATE;
205 1583 : spdm_response->header.param1 = slot_id;
206 1583 : spdm_response->header.param2 = 0;
207 1583 : 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 1583 : 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 1583 : 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 1583 : 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 1583 : spdm_response->portion_length = (uint16_t)length;
229 1583 : 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 1583 : if (length != 0) {
235 1580 : 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 1580 : .local_cert_chain_provision[slot_id] + offset, length);
239 : }
240 :
241 1583 : if (session_info == NULL) {
242 : /* Log to transcript. */
243 1578 : const size_t spdm_request_size = req_msg_header_size;
244 :
245 1578 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
246 1578 : 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 1578 : status = libspdm_append_message_b(spdm_context, spdm_response, *response_size);
253 1578 : 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 1583 : if (spdm_context->connection_info.connection_state <
261 : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE) {
262 14 : libspdm_set_connection_state(spdm_context, LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE);
263 : }
264 :
265 1583 : return LIBSPDM_STATUS_SUCCESS;
266 : }
267 :
268 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
|