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 :
7 : #include "internal/libspdm_responder_lib.h"
8 :
9 : #if (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT)
10 :
11 2 : libspdm_return_t libspdm_get_encap_request_get_certificate(libspdm_context_t *spdm_context,
12 : size_t *encap_request_size,
13 : void *encap_request)
14 : {
15 : spdm_get_certificate_large_request_t *spdm_request;
16 : libspdm_return_t status;
17 : uint32_t req_msg_length;
18 : uint32_t req_msg_offset;
19 : bool use_large_cert_chain;
20 : uint32_t req_msg_header_size;
21 :
22 2 : spdm_context->encap_context.last_encap_request_size = 0;
23 :
24 2 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
25 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
26 : }
27 :
28 2 : if (!libspdm_is_capabilities_flag_supported(
29 : spdm_context, false,
30 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, 0)) {
31 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
32 : }
33 :
34 2 : if ((libspdm_get_connection_version (spdm_context) >= SPDM_MESSAGE_VERSION_14) &&
35 0 : libspdm_is_capabilities_flag_supported(
36 : spdm_context, false,
37 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_LARGE_RESP_CAP, 0)) {
38 0 : use_large_cert_chain = true;
39 0 : spdm_context->encap_context.use_large_cert_chain = true;
40 : } else {
41 2 : use_large_cert_chain = false;
42 2 : spdm_context->encap_context.use_large_cert_chain = false;
43 : }
44 :
45 2 : if (use_large_cert_chain) {
46 0 : req_msg_header_size = sizeof(spdm_get_certificate_large_request_t);
47 : } else {
48 2 : req_msg_header_size = sizeof(spdm_get_certificate_request_t);
49 : }
50 :
51 2 : LIBSPDM_ASSERT(*encap_request_size >= req_msg_header_size);
52 2 : *encap_request_size = req_msg_header_size;
53 :
54 2 : spdm_request = encap_request;
55 :
56 2 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
57 2 : spdm_request->header.request_response_code = SPDM_GET_CERTIFICATE;
58 2 : spdm_request->header.param1 = spdm_context->encap_context.req_slot_id;
59 2 : spdm_request->header.param2 = 0;
60 2 : req_msg_offset = (uint32_t)spdm_context->mut_auth_cert_chain_buffer_size;
61 2 : req_msg_length = LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN;
62 2 : if (use_large_cert_chain) {
63 0 : spdm_request->header.param1 |= SPDM_GET_CERTIFICATE_REQUEST_LARGE_CERT_CHAIN;
64 0 : spdm_request->offset = 0;
65 0 : spdm_request->length = 0;
66 0 : spdm_request->large_offset = req_msg_offset;
67 0 : spdm_request->large_length = req_msg_length;
68 : } else {
69 2 : spdm_request->offset = (uint16_t)req_msg_offset;
70 2 : spdm_request->length = (uint16_t)req_msg_length;
71 : }
72 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "request (offset 0x%x, size 0x%x):\n",
73 : req_msg_offset, req_msg_length));
74 :
75 2 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
76 2 : spdm_request->header.request_response_code);
77 :
78 : /* Cache data*/
79 2 : status = libspdm_append_message_mut_b(spdm_context, spdm_request, *encap_request_size);
80 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
81 0 : return LIBSPDM_STATUS_BUFFER_FULL;
82 : }
83 :
84 2 : libspdm_copy_mem(&spdm_context->encap_context.last_encap_request_header,
85 : sizeof(spdm_context->encap_context.last_encap_request_header),
86 2 : &spdm_request->header, sizeof(spdm_message_header_t));
87 2 : spdm_context->encap_context.last_encap_request_size = *encap_request_size;
88 :
89 2 : return LIBSPDM_STATUS_SUCCESS;
90 : }
91 :
92 12 : libspdm_return_t libspdm_process_encap_response_certificate(
93 : libspdm_context_t *spdm_context, size_t encap_response_size,
94 : const void *encap_response, bool *need_continue)
95 : {
96 : const spdm_certificate_large_response_t *spdm_response;
97 : size_t spdm_response_size;
98 : bool result;
99 : libspdm_return_t status;
100 : uint32_t request_offset;
101 : uint8_t slot_id;
102 : uint8_t *cert_chain_buffer;
103 : size_t cert_chain_buffer_size;
104 : size_t cert_chain_buffer_max_size;
105 : uint8_t cert_model;
106 : uint32_t rsp_msg_portion_length;
107 : uint32_t rsp_msg_remainder_length;
108 : bool use_large_cert_chain;
109 : uint32_t rsp_msg_header_size;
110 : uint32_t max_cert_chain_size;
111 :
112 12 : spdm_response = encap_response;
113 12 : spdm_response_size = encap_response_size;
114 :
115 12 : cert_chain_buffer = (uint8_t *)spdm_context->mut_auth_cert_chain_buffer;
116 12 : cert_chain_buffer_size = spdm_context->mut_auth_cert_chain_buffer_size;
117 12 : cert_chain_buffer_max_size = spdm_context->mut_auth_cert_chain_buffer_max_size;
118 :
119 12 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
120 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
121 : }
122 12 : if (spdm_response->header.spdm_version != libspdm_get_connection_version (spdm_context)) {
123 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
124 : }
125 12 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
126 2 : status = libspdm_handle_encap_error_response_main(
127 2 : spdm_context, spdm_response->header.param1);
128 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
129 2 : return status;
130 : }
131 10 : } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
132 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
133 : }
134 10 : use_large_cert_chain = spdm_context->encap_context.use_large_cert_chain;
135 10 : if (use_large_cert_chain) {
136 0 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) == 0) {
137 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
138 : }
139 : } else {
140 10 : if ((spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_14) &&
141 0 : ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_LARGE_CERT_CHAIN) != 0)) {
142 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
143 : }
144 : }
145 :
146 10 : if (use_large_cert_chain) {
147 0 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE_14;
148 0 : rsp_msg_header_size = sizeof(spdm_certificate_large_response_t);
149 : } else {
150 10 : max_cert_chain_size = SPDM_MAX_CERTIFICATE_CHAIN_SIZE;
151 10 : rsp_msg_header_size = sizeof(spdm_certificate_response_t);
152 : }
153 :
154 10 : if (encap_response_size < rsp_msg_header_size) {
155 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
156 : }
157 10 : if (use_large_cert_chain) {
158 0 : rsp_msg_portion_length = spdm_response->large_portion_length;
159 0 : rsp_msg_remainder_length = spdm_response->large_remainder_length;
160 : } else {
161 10 : rsp_msg_portion_length = spdm_response->portion_length;
162 10 : rsp_msg_remainder_length = spdm_response->remainder_length;
163 : }
164 :
165 10 : if ((rsp_msg_portion_length > LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN) ||
166 : (rsp_msg_portion_length == 0)) {
167 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
168 : }
169 :
170 8 : request_offset = (uint32_t)cert_chain_buffer_size;
171 :
172 8 : if (rsp_msg_portion_length > max_cert_chain_size - request_offset) {
173 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
174 : }
175 8 : if (rsp_msg_remainder_length > max_cert_chain_size - request_offset - rsp_msg_portion_length) {
176 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
177 : }
178 8 : if (request_offset == 0) {
179 8 : spdm_context->encap_context.cert_chain_total_len = rsp_msg_portion_length +
180 : rsp_msg_remainder_length;
181 0 : } else if (spdm_context->encap_context.cert_chain_total_len !=
182 0 : request_offset + rsp_msg_portion_length + rsp_msg_remainder_length) {
183 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
184 : }
185 8 : slot_id = spdm_context->encap_context.req_slot_id;
186 8 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
187 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
188 : }
189 8 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
190 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
191 : spdm_response->header.param2));
192 6 : cert_model = spdm_response->header.param2 &
193 : SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
194 6 : if (spdm_context->connection_info.multi_key_conn_req) {
195 5 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
196 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
197 : }
198 5 : if ((slot_id == 0) &&
199 : (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
200 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
201 : }
202 4 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
203 1 : (spdm_response->portion_length != 0)) {
204 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
205 : }
206 : } else {
207 1 : if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
208 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
209 : }
210 : }
211 4 : if (spdm_context->connection_info.peer_cert_info[slot_id] ==
212 : SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
213 4 : spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
214 0 : } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
215 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
216 : }
217 : }
218 :
219 6 : if (spdm_response_size < rsp_msg_header_size + rsp_msg_portion_length) {
220 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
221 : }
222 6 : spdm_response_size = rsp_msg_header_size + rsp_msg_portion_length;
223 :
224 : /* Cache data*/
225 :
226 6 : status = libspdm_append_message_mut_b(spdm_context, spdm_response, spdm_response_size);
227 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
228 0 : return LIBSPDM_STATUS_BUFFER_FULL;
229 : }
230 :
231 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
232 : request_offset, rsp_msg_portion_length));
233 6 : LIBSPDM_INTERNAL_DUMP_HEX((const uint8_t *)spdm_response + rsp_msg_header_size,
234 : rsp_msg_portion_length);
235 :
236 6 : if (cert_chain_buffer_size + rsp_msg_portion_length > cert_chain_buffer_max_size) {
237 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_chain_buffer full\n"));
238 0 : return LIBSPDM_STATUS_BUFFER_FULL;
239 : }
240 :
241 6 : libspdm_copy_mem(cert_chain_buffer + cert_chain_buffer_size,
242 : cert_chain_buffer_max_size - cert_chain_buffer_size,
243 : (const uint8_t *)spdm_response + rsp_msg_header_size,
244 : rsp_msg_portion_length);
245 :
246 6 : cert_chain_buffer_size += rsp_msg_portion_length;
247 6 : spdm_context->mut_auth_cert_chain_buffer_size = cert_chain_buffer_size;
248 :
249 6 : if (rsp_msg_remainder_length != 0) {
250 6 : *need_continue = true;
251 :
252 6 : return LIBSPDM_STATUS_SUCCESS;
253 : }
254 :
255 0 : *need_continue = false;
256 :
257 0 : if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
258 0 : result = spdm_context->local_context.verify_peer_spdm_cert_chain (
259 0 : spdm_context, spdm_context->encap_context.req_slot_id,
260 : cert_chain_buffer_size, cert_chain_buffer, NULL, NULL);
261 0 : if (!result) {
262 0 : return LIBSPDM_STATUS_VERIF_FAIL;
263 : }
264 : } else {
265 0 : result = libspdm_verify_peer_cert_chain_buffer_integrity(
266 : spdm_context, cert_chain_buffer, cert_chain_buffer_size);
267 0 : if (!result) {
268 0 : return LIBSPDM_STATUS_VERIF_FAIL;
269 : }
270 :
271 : /*verify peer cert chain authority*/
272 0 : result = libspdm_verify_peer_cert_chain_buffer_authority(
273 : spdm_context, cert_chain_buffer, cert_chain_buffer_size, NULL, NULL);
274 0 : if (!result) {
275 0 : status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
276 : }
277 : }
278 :
279 0 : spdm_context->connection_info.peer_used_cert_chain_slot_id =
280 0 : spdm_context->encap_context.req_slot_id;
281 0 : slot_id = spdm_context->encap_context.req_slot_id;
282 0 : LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
283 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
284 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
285 : cert_chain_buffer_size;
286 :
287 : libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
288 : sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
289 : cert_chain_buffer, cert_chain_buffer_size);
290 : #else
291 0 : result = libspdm_hash_all(
292 : spdm_context->connection_info.algorithm.base_hash_algo,
293 : cert_chain_buffer, cert_chain_buffer_size,
294 0 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
295 0 : if (!result) {
296 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
297 : }
298 0 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
299 0 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
300 :
301 0 : if (spdm_context->connection_info.algorithm.req_pqc_asym_alg != 0) {
302 0 : result = libspdm_get_pqc_leaf_cert_public_key_from_cert_chain(
303 : spdm_context->connection_info.algorithm.base_hash_algo,
304 : spdm_context->connection_info.algorithm.req_pqc_asym_alg,
305 : cert_chain_buffer, cert_chain_buffer_size,
306 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
307 : } else {
308 0 : result = libspdm_get_leaf_cert_public_key_from_cert_chain(
309 : spdm_context->connection_info.algorithm.base_hash_algo,
310 0 : spdm_context->connection_info.algorithm.req_base_asym_alg,
311 : cert_chain_buffer, cert_chain_buffer_size,
312 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
313 : }
314 0 : if (!result) {
315 0 : return LIBSPDM_STATUS_INVALID_CERT;
316 : }
317 : #endif
318 0 : if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
319 0 : return LIBSPDM_STATUS_SUCCESS;
320 : } else {
321 0 : return LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
322 : }
323 : }
324 :
325 : #endif /* (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && (...) */
|