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_MUT_AUTH_CAP) && (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) && \
10 : (LIBSPDM_SEND_GET_CERTIFICATE_SUPPORT)
11 :
12 2 : libspdm_return_t libspdm_get_encap_request_get_certificate(libspdm_context_t *spdm_context,
13 : size_t *encap_request_size,
14 : void *encap_request)
15 : {
16 : spdm_get_certificate_request_t *spdm_request;
17 : libspdm_return_t status;
18 :
19 2 : spdm_context->encap_context.last_encap_request_size = 0;
20 :
21 2 : if (libspdm_get_connection_version(spdm_context) < SPDM_MESSAGE_VERSION_11) {
22 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
23 : }
24 :
25 2 : if (!libspdm_is_capabilities_flag_supported(
26 : spdm_context, false,
27 : SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, 0)) {
28 0 : return LIBSPDM_STATUS_UNSUPPORTED_CAP;
29 : }
30 :
31 2 : LIBSPDM_ASSERT(*encap_request_size >= sizeof(spdm_get_certificate_request_t));
32 2 : *encap_request_size = sizeof(spdm_get_certificate_request_t);
33 :
34 2 : spdm_request = encap_request;
35 :
36 2 : spdm_request->header.spdm_version = libspdm_get_connection_version (spdm_context);
37 2 : spdm_request->header.request_response_code = SPDM_GET_CERTIFICATE;
38 2 : spdm_request->header.param1 = spdm_context->encap_context.req_slot_id;
39 2 : spdm_request->header.param2 = 0;
40 2 : spdm_request->offset = (uint16_t)spdm_context->mut_auth_cert_chain_buffer_size;
41 2 : spdm_request->length = LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN;
42 2 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "request (offset 0x%x, size 0x%x):\n",
43 : spdm_request->offset, spdm_request->length));
44 :
45 2 : libspdm_reset_message_buffer_via_request_code(spdm_context, NULL,
46 2 : spdm_request->header.request_response_code);
47 :
48 : /* Cache data*/
49 2 : status = libspdm_append_message_mut_b(spdm_context, spdm_request, *encap_request_size);
50 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
51 0 : return LIBSPDM_STATUS_BUFFER_FULL;
52 : }
53 :
54 2 : libspdm_copy_mem(&spdm_context->encap_context.last_encap_request_header,
55 : sizeof(spdm_context->encap_context.last_encap_request_header),
56 2 : &spdm_request->header, sizeof(spdm_message_header_t));
57 2 : spdm_context->encap_context.last_encap_request_size = *encap_request_size;
58 :
59 2 : return LIBSPDM_STATUS_SUCCESS;
60 : }
61 :
62 12 : libspdm_return_t libspdm_process_encap_response_certificate(
63 : libspdm_context_t *spdm_context, size_t encap_response_size,
64 : const void *encap_response, bool *need_continue)
65 : {
66 : const spdm_certificate_response_t *spdm_response;
67 : size_t spdm_response_size;
68 : bool result;
69 : libspdm_return_t status;
70 : uint16_t request_offset;
71 : uint8_t slot_id;
72 : uint8_t *cert_chain_buffer;
73 : size_t cert_chain_buffer_size;
74 : size_t cert_chain_buffer_max_size;
75 : uint8_t cert_model;
76 :
77 12 : spdm_response = encap_response;
78 12 : spdm_response_size = encap_response_size;
79 :
80 12 : cert_chain_buffer = (uint8_t *)spdm_context->mut_auth_cert_chain_buffer;
81 12 : cert_chain_buffer_size = spdm_context->mut_auth_cert_chain_buffer_size;
82 12 : cert_chain_buffer_max_size = spdm_context->mut_auth_cert_chain_buffer_max_size;
83 :
84 12 : if (spdm_response_size < sizeof(spdm_message_header_t)) {
85 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
86 : }
87 12 : if (spdm_response->header.spdm_version != libspdm_get_connection_version (spdm_context)) {
88 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
89 : }
90 12 : if (spdm_response->header.request_response_code == SPDM_ERROR) {
91 2 : status = libspdm_handle_encap_error_response_main(
92 2 : spdm_context, spdm_response->header.param1);
93 2 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
94 2 : return status;
95 : }
96 10 : } else if (spdm_response->header.request_response_code != SPDM_CERTIFICATE) {
97 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
98 : }
99 10 : if (encap_response_size < sizeof(spdm_certificate_response_t)) {
100 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
101 : }
102 10 : if ((spdm_response->portion_length > LIBSPDM_MAX_CERT_CHAIN_BLOCK_LEN) ||
103 9 : (spdm_response->portion_length == 0)) {
104 2 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
105 : }
106 :
107 8 : request_offset = (uint16_t)cert_chain_buffer_size;
108 :
109 8 : if (spdm_response->portion_length > 0xFFFF - request_offset) {
110 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
111 : }
112 8 : if (spdm_response->remainder_length > 0xFFFF - request_offset - spdm_response->portion_length) {
113 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
114 : }
115 8 : if (request_offset == 0) {
116 8 : spdm_context->encap_context.cert_chain_total_len = spdm_response->portion_length +
117 8 : spdm_response->remainder_length;
118 0 : } else if (spdm_context->encap_context.cert_chain_total_len !=
119 0 : request_offset + spdm_response->portion_length + spdm_response->remainder_length) {
120 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
121 : }
122 8 : slot_id = spdm_context->encap_context.req_slot_id;
123 8 : if ((spdm_response->header.param1 & SPDM_CERTIFICATE_RESPONSE_SLOT_ID_MASK) != slot_id) {
124 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
125 : }
126 8 : if (spdm_response->header.spdm_version >= SPDM_MESSAGE_VERSION_13) {
127 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "cert_info - 0x%02x\n",
128 : spdm_response->header.param2));
129 6 : cert_model = spdm_response->header.param2 &
130 : SPDM_CERTIFICATE_RESPONSE_ATTRIBUTES_CERTIFICATE_INFO_MASK;
131 6 : if (spdm_context->connection_info.multi_key_conn_req) {
132 5 : if (cert_model > SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT) {
133 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
134 : }
135 5 : if ((slot_id == 0) &&
136 : (cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_GENERIC_CERT)) {
137 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
138 : }
139 4 : if ((cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) &&
140 1 : (spdm_response->portion_length != 0)) {
141 1 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
142 : }
143 : } else {
144 1 : if (cert_model != SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
145 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
146 : }
147 : }
148 4 : if (spdm_context->connection_info.peer_cert_info[slot_id] ==
149 : SPDM_CERTIFICATE_INFO_CERT_MODEL_NONE) {
150 4 : spdm_context->connection_info.peer_cert_info[slot_id] = cert_model;
151 0 : } else if (spdm_context->connection_info.peer_cert_info[slot_id] != cert_model) {
152 0 : return LIBSPDM_STATUS_INVALID_MSG_FIELD;
153 : }
154 : }
155 :
156 6 : if (spdm_response_size < sizeof(spdm_certificate_response_t) + spdm_response->portion_length) {
157 0 : return LIBSPDM_STATUS_INVALID_MSG_SIZE;
158 : }
159 6 : spdm_response_size = sizeof(spdm_certificate_response_t) + spdm_response->portion_length;
160 :
161 : /* Cache data*/
162 :
163 6 : status = libspdm_append_message_mut_b(spdm_context, spdm_response, spdm_response_size);
164 6 : if (LIBSPDM_STATUS_IS_ERROR(status)) {
165 0 : return LIBSPDM_STATUS_BUFFER_FULL;
166 : }
167 :
168 6 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO, "Certificate (offset 0x%x, size 0x%x):\n",
169 : request_offset, spdm_response->portion_length));
170 6 : LIBSPDM_INTERNAL_DUMP_HEX((const void *)(spdm_response + 1), spdm_response->portion_length);
171 :
172 6 : if ((cert_chain_buffer_size + spdm_response->portion_length) > cert_chain_buffer_max_size) {
173 0 : return LIBSPDM_STATUS_BUFFER_FULL;
174 : }
175 :
176 6 : libspdm_copy_mem(cert_chain_buffer + cert_chain_buffer_size,
177 : cert_chain_buffer_max_size - cert_chain_buffer_size,
178 6 : (const void *)(spdm_response + 1), spdm_response->portion_length);
179 :
180 6 : cert_chain_buffer_size += spdm_response->portion_length;
181 6 : spdm_context->mut_auth_cert_chain_buffer_size = cert_chain_buffer_size;
182 :
183 6 : if (spdm_response->remainder_length != 0) {
184 6 : *need_continue = true;
185 :
186 6 : return LIBSPDM_STATUS_SUCCESS;
187 : }
188 :
189 0 : *need_continue = false;
190 :
191 0 : if (spdm_context->local_context.verify_peer_spdm_cert_chain != NULL) {
192 0 : result = spdm_context->local_context.verify_peer_spdm_cert_chain (
193 0 : spdm_context, spdm_context->encap_context.req_slot_id,
194 : cert_chain_buffer_size, cert_chain_buffer, NULL, NULL);
195 0 : if (!result) {
196 0 : return LIBSPDM_STATUS_VERIF_FAIL;
197 : }
198 : } else {
199 0 : result = libspdm_verify_peer_cert_chain_buffer_integrity(
200 : spdm_context, cert_chain_buffer, cert_chain_buffer_size);
201 0 : if (!result) {
202 0 : return LIBSPDM_STATUS_VERIF_FAIL;
203 : }
204 :
205 : /*verify peer cert chain authority*/
206 0 : result = libspdm_verify_peer_cert_chain_buffer_authority(
207 : spdm_context, cert_chain_buffer, cert_chain_buffer_size, NULL, NULL);
208 0 : if (!result) {
209 0 : status = LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
210 : }
211 : }
212 :
213 0 : spdm_context->connection_info.peer_used_cert_chain_slot_id =
214 0 : spdm_context->encap_context.req_slot_id;
215 0 : slot_id = spdm_context->encap_context.req_slot_id;
216 0 : LIBSPDM_ASSERT(slot_id < SPDM_MAX_SLOT_COUNT);
217 : #if LIBSPDM_RECORD_TRANSCRIPT_DATA_SUPPORT
218 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_size =
219 : cert_chain_buffer_size;
220 :
221 : libspdm_copy_mem(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer,
222 : sizeof(spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer),
223 : cert_chain_buffer, cert_chain_buffer_size);
224 : #else
225 0 : result = libspdm_hash_all(
226 : spdm_context->connection_info.algorithm.base_hash_algo,
227 : cert_chain_buffer, cert_chain_buffer_size,
228 0 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash);
229 0 : if (!result) {
230 0 : return LIBSPDM_STATUS_CRYPTO_ERROR;
231 : }
232 0 : spdm_context->connection_info.peer_used_cert_chain[slot_id].buffer_hash_size =
233 0 : libspdm_get_hash_size(spdm_context->connection_info.algorithm.base_hash_algo);
234 :
235 0 : result = libspdm_get_leaf_cert_public_key_from_cert_chain(
236 : spdm_context->connection_info.algorithm.base_hash_algo,
237 0 : spdm_context->connection_info.algorithm.req_base_asym_alg,
238 : cert_chain_buffer, cert_chain_buffer_size,
239 0 : &spdm_context->connection_info.peer_used_cert_chain[slot_id].leaf_cert_public_key);
240 0 : if (!result) {
241 0 : return LIBSPDM_STATUS_INVALID_CERT;
242 : }
243 : #endif
244 0 : if (status != LIBSPDM_STATUS_VERIF_NO_AUTHORITY) {
245 0 : return LIBSPDM_STATUS_SUCCESS;
246 : } else {
247 0 : return LIBSPDM_STATUS_VERIF_NO_AUTHORITY;
248 : }
249 : }
250 :
251 : #endif /* (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) && (...) */
|