Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2021-2025 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 1650 : 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 : uint32_t req_msg_header_size;
28 : uint32_t rsp_msg_header_size;
29 : size_t cert_chain_size;
30 : uint32_t max_cert_chain_block_size;
31 :
32 1650 : spdm_request = request;
33 :
34 : /* -=[Check Parameters Phase]=- */
35 1650 : LIBSPDM_ASSERT(spdm_request->header.request_response_code == SPDM_GET_CERTIFICATE);
36 :
37 1650 : if (spdm_request->header.spdm_version != libspdm_get_connection_version(spdm_context)) {
38 0 : return libspdm_generate_error_response(spdm_context,
39 : SPDM_ERROR_CODE_VERSION_MISMATCH, 0,
40 : response_size, response);
41 : }
42 1650 : if (spdm_context->response_state != LIBSPDM_RESPONSE_STATE_NORMAL) {
43 3 : return libspdm_responder_handle_response_state(
44 : spdm_context,
45 3 : spdm_request->header.request_response_code,
46 : response_size, response);
47 : }
48 1647 : if (spdm_context->connection_info.connection_state < LIBSPDM_CONNECTION_STATE_NEGOTIATED) {
49 1 : return libspdm_generate_error_response(spdm_context,
50 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST,
51 : 0, response_size, response);
52 : }
53 1646 : session_info = NULL;
54 1646 : if (spdm_context->last_spdm_request_session_id_valid) {
55 6 : session_info = libspdm_get_session_info_via_session_id(
56 : spdm_context,
57 : spdm_context->last_spdm_request_session_id);
58 6 : if (session_info == NULL) {
59 0 : return libspdm_generate_error_response(
60 : spdm_context,
61 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
62 : response_size, response);
63 : }
64 6 : session_state = libspdm_secured_message_get_session_state(
65 : session_info->secured_message_context);
66 6 : if (session_state != LIBSPDM_SESSION_STATE_ESTABLISHED) {
67 0 : return libspdm_generate_error_response(
68 : spdm_context,
69 : SPDM_ERROR_CODE_UNEXPECTED_REQUEST, 0,
70 : response_size, response);
71 : }
72 : }
73 1646 : if (!libspdm_is_capabilities_flag_supported(
74 : spdm_context, false, 0,
75 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP)) {
76 0 : return libspdm_generate_error_response(
77 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
78 : SPDM_GET_CERTIFICATE, response_size, response);
79 : }
80 :
81 1646 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
82 0 : ((spdm_request->header.param1 & SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN) != 0)) {
83 0 : if (!libspdm_is_capabilities_flag_supported(
84 : spdm_context, false, 0,
85 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_LARGE_RESP_CAP)) {
86 0 : return libspdm_generate_error_response(
87 : spdm_context, SPDM_ERROR_CODE_UNSUPPORTED_REQUEST,
88 : SPDM_GET_CERTIFICATE, response_size, response);
89 : }
90 0 : use_large_cert_chain = true;
91 : } else {
92 1646 : use_large_cert_chain = false;
93 : }
94 :
95 1646 : if (use_large_cert_chain) {
96 0 : req_msg_header_size = sizeof(spdm_get_certificate_large_request_t);
97 0 : rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
98 : } else {
99 1646 : req_msg_header_size = sizeof(spdm_get_certificate_request_t);
100 1646 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
101 : }
102 :
103 1646 : if (request_size < req_msg_header_size) {
104 0 : return libspdm_generate_error_response(spdm_context,
105 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
106 : response_size, response);
107 : }
108 :
109 1646 : slot_id = spdm_request->header.param1 & SPDM_GET_CERTIFICATE_REQUEST_SLOT_ID_MASK;
110 :
111 1646 : if (slot_id >= SPDM_MAX_SLOT_COUNT) {
112 1 : return libspdm_generate_error_response(spdm_context,
113 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
114 : response_size, response);
115 : }
116 :
117 1645 : if ((spdm_context->local_context.cert_slot_reset_mask & (1 << slot_id)) != 0) {
118 1 : LIBSPDM_ASSERT(spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_12);
119 1 : return libspdm_generate_error_response(spdm_context,
120 : SPDM_ERROR_CODE_RESET_REQUIRED, 0,
121 : response_size, response);
122 : }
123 :
124 1644 : if (spdm_context->local_context.local_cert_chain_provision[slot_id] == NULL) {
125 0 : return libspdm_generate_error_response(
126 : spdm_context, SPDM_ERROR_CODE_INVALID_REQUEST,
127 : 0, response_size, response);
128 : }
129 :
130 1644 : cert_chain_size = spdm_context->local_context.local_cert_chain_provision_size[slot_id];
131 :
132 1644 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
133 0 : (!use_large_cert_chain) && (cert_chain_size > SPDM_MAX_CERTIFICATE_CHAIN_SIZE)) {
134 0 : return libspdm_generate_extended_error_response(
135 : spdm_context, SPDM_ERROR_CODE_DATA_TOO_LARGE, 0,
136 : sizeof(spdm_error_data_cert_chain_too_large_t),
137 : (const uint8_t *)&cert_chain_size,
138 : response_size, response);
139 : }
140 :
141 1644 : if (use_large_cert_chain) {
142 0 : offset = spdm_request->large_offset;
143 0 : length = spdm_request->large_length;
144 : } else {
145 1644 : offset = spdm_request->offset;
146 1644 : length = spdm_request->length;
147 : }
148 :
149 1644 : if (spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
150 1 : if (spdm_request->header.param2 &
151 : SPDM_GET_CERTIFICATE_REQUEST_ATTRIBUTES_SLOT_SIZE_REQUESTED) {
152 1 : offset = 0;
153 1 : length = 0;
154 : }
155 : }
156 :
157 1644 : if (offset >= cert_chain_size) {
158 126 : return libspdm_generate_error_response(spdm_context,
159 : SPDM_ERROR_CODE_INVALID_REQUEST, 0,
160 : response_size, response);
161 : }
162 :
163 1518 : if (!libspdm_is_capabilities_flag_supported(spdm_context, false,
164 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP,
165 : SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP)) {
166 1515 : max_cert_chain_block_size = (uint32_t) (*response_size - rsp_msg_header_size);
167 1515 : if (!use_large_cert_chain){
168 1515 : max_cert_chain_block_size = LIBSPDM_MIN(max_cert_chain_block_size, SPDM_MAX_CERTIFICATE_CHAIN_SIZE);
169 : }
170 :
171 1515 : if (length > max_cert_chain_block_size) {
172 67 : length = max_cert_chain_block_size;
173 : }
174 : }
175 :
176 1518 : if ((size_t)(offset + length) > cert_chain_size) {
177 18 : length = (uint32_t)(cert_chain_size - offset);
178 : }
179 1518 : remainder_length = (uint32_t)(cert_chain_size - (length + offset));
180 :
181 1518 : libspdm_reset_message_buffer_via_request_code(spdm_context, session_info,
182 1518 : spdm_request->header.request_response_code);
183 :
184 1518 : LIBSPDM_ASSERT(*response_size >= rsp_msg_header_size + length);
185 1518 : response_capacity = *response_size;
186 1518 : *response_size = rsp_msg_header_size + length;
187 1518 : libspdm_zero_mem(response, *response_size);
188 1518 : spdm_response = response;
189 :
190 1518 : spdm_response->header.spdm_version = spdm_request->header.spdm_version;
191 1518 : spdm_response->header.request_response_code = SPDM_CERTIFICATE;
192 1518 : spdm_response->header.param1 = slot_id;
193 1518 : spdm_response->header.param2 = 0;
194 1518 : if ((spdm_request->header.spdm_version >= SPDM_MESSAGE_VERSION_13) &&
195 1 : spdm_context->connection_info.multi_key_conn_rsp) {
196 0 : spdm_response->header.param2 = spdm_context->local_context.local_cert_info[slot_id];
197 : }
198 1518 : if (use_large_cert_chain) {
199 0 : spdm_response->header.param1 |= SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN;
200 : }
201 :
202 1518 : if (use_large_cert_chain) {
203 0 : spdm_response->portion_length = 0;
204 0 : spdm_response->remainder_length = 0;
205 0 : spdm_response->large_portion_length = length;
206 0 : spdm_response->large_remainder_length = remainder_length;
207 : } else {
208 1518 : spdm_response->portion_length = (uint16_t)length;
209 1518 : spdm_response->remainder_length = (uint16_t)remainder_length;
210 : }
211 :
212 1518 : libspdm_copy_mem((uint8_t *)spdm_response + rsp_msg_header_size,
213 : response_capacity - rsp_msg_header_size,
214 : (const uint8_t *)spdm_context->local_context
215 1518 : .local_cert_chain_provision[slot_id] + offset, length);
216 :
217 1518 : if (session_info == NULL) {
218 : /* Log to transcript. */
219 1514 : const size_t spdm_request_size = req_msg_header_size;
220 :
221 1514 : status = libspdm_append_message_b(spdm_context, spdm_request, spdm_request_size);
222 1514 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
223 0 : return libspdm_generate_error_response(spdm_context,
224 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
225 : response_size, response);
226 : }
227 :
228 1514 : status = libspdm_append_message_b(spdm_context, spdm_response, *response_size);
229 1514 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
230 0 : return libspdm_generate_error_response(spdm_context,
231 : SPDM_ERROR_CODE_UNSPECIFIED, 0,
232 : response_size, response);
233 : }
234 : }
235 :
236 1518 : if (spdm_context->connection_info.connection_state <
237 : LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE) {
238 13 : libspdm_set_connection_state(spdm_context, LIBSPDM_CONNECTION_STATE_AFTER_CERTIFICATE);
239 : }
240 :
241 1518 : return LIBSPDM_STATUS_SUCCESS;
242 : }
243 :
244 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CERT_CAP */
|