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