Line data Source code
1 : /**
2 : * Copyright Notice:
3 : * Copyright 2024-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 :
7 : #include <stdarg.h>
8 : #include <stddef.h>
9 : #include <setjmp.h>
10 : #include <stdint.h>
11 : #include <stdlib.h>
12 : #include <stdio.h>
13 : #include <assert.h>
14 : #include <string.h>
15 :
16 : #include <base.h>
17 : #include "library/memlib.h"
18 : #include "internal/libspdm_device_secret_lib.h"
19 : #include "internal/libspdm_common_lib.h"
20 :
21 : #if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP
22 19 : bool libspdm_read_cached_last_csr_request(uint8_t **last_csr_request,
23 : size_t *last_csr_request_len,
24 : uint8_t req_csr_tracking_tag,
25 : uint8_t *available_rsp_csr_tracking_tag)
26 : {
27 : bool res;
28 : uint8_t index;
29 : size_t file_size;
30 : uint8_t *file_data;
31 :
32 19 : file_data = NULL;
33 19 : *available_rsp_csr_tracking_tag = 0;
34 19 : char file[] = "cached_last_csr_x_request";
35 : /*change the file name, for example: cached_last_csr_1_request*/
36 19 : file[16] = (char)(req_csr_tracking_tag + '0');
37 19 : res = libspdm_read_input_file(file, (void **)last_csr_request, last_csr_request_len);
38 :
39 152 : for (index = 1; index <= SPDM_MAX_CSR_TRACKING_TAG; index++) {
40 133 : file[16] = (char)(index + '0');
41 133 : libspdm_read_input_file(file, (void **)(&file_data), &file_size);
42 133 : if (file_size == 0) {
43 85 : *available_rsp_csr_tracking_tag |= (1 << index);
44 : } else {
45 48 : if (file_data != NULL) {
46 35 : free(file_data);
47 : }
48 : }
49 : }
50 :
51 19 : return res;
52 : }
53 :
54 13 : bool libspdm_cache_last_csr_request(const uint8_t *last_csr_request,
55 : size_t last_csr_request_len,
56 : uint8_t req_csr_tracking_tag)
57 : {
58 : bool res;
59 :
60 13 : char file[] = "cached_last_csr_x_request";
61 : /*change the file name, for example: cached_last_csr_1_request*/
62 13 : file[16] = (char)(req_csr_tracking_tag + '0');
63 13 : res = libspdm_write_output_file(file, last_csr_request, last_csr_request_len);
64 :
65 13 : return res;
66 : }
67 :
68 : /*clean the cached last SPDM csr request*/
69 1 : bool libspdm_discard_all_cached_last_request()
70 : {
71 : uint8_t index;
72 :
73 1 : char file[] = "cached_last_csr_x_request";
74 :
75 8 : for (index = 1; index <= SPDM_MAX_CSR_TRACKING_TAG; index++) {
76 7 : file[16] = (char)(index + '0');
77 7 : if (!libspdm_write_output_file(file, NULL, 0)) {
78 0 : return false;
79 : }
80 : }
81 :
82 1 : return true;
83 : }
84 :
85 : /*
86 : * return true represent that: the device complete the csr by reset successfully
87 : * return false represent that: the device complete the csr need reset
88 : **/
89 4 : bool libspdm_read_cached_csr(uint8_t **csr_pointer, size_t *csr_len)
90 : {
91 : bool res;
92 : char *file;
93 :
94 4 : file = "test_csr/cached.csr";
95 :
96 4 : res = libspdm_read_input_file(file, (void **)csr_pointer, csr_len);
97 4 : return res;
98 : }
99 :
100 6 : bool libspdm_gen_csr_without_reset(uint32_t base_hash_algo, uint32_t base_asym_algo,
101 : uint32_t pqc_asym_algo,
102 : uint8_t *requester_info, size_t requester_info_length,
103 : uint8_t *opaque_data, uint16_t opaque_data_length,
104 : size_t *csr_len, uint8_t *csr_pointer,
105 : bool is_device_cert_model)
106 : {
107 : bool result;
108 : size_t hash_nid;
109 : size_t asym_nid;
110 : size_t pqc_asym_nid;
111 : void *context;
112 : size_t csr_buffer_size;
113 :
114 6 : csr_buffer_size = *csr_len;
115 :
116 : #if !LIBSPDM_PRIVATE_KEY_MODE_RAW_KEY_ONLY
117 6 : if (g_private_key_mode) {
118 : void *x509_ca_cert;
119 : void *prikey, *cert;
120 : size_t prikey_size, cert_size;
121 :
122 6 : if (pqc_asym_algo != 0) {
123 0 : result = libspdm_read_responder_pqc_private_key(
124 : pqc_asym_algo, &prikey, &prikey_size);
125 : } else {
126 6 : result = libspdm_read_responder_private_key(
127 : base_asym_algo, &prikey, &prikey_size);
128 : }
129 6 : if (!result) {
130 0 : return false;
131 : }
132 :
133 6 : if (pqc_asym_algo != 0) {
134 0 : result = libspdm_read_responder_pqc_certificate(
135 : pqc_asym_algo, &cert, &cert_size);
136 : } else {
137 6 : result = libspdm_read_responder_certificate(
138 : base_asym_algo, &cert, &cert_size);
139 : }
140 6 : if (!result) {
141 0 : return false;
142 : }
143 :
144 6 : result = libspdm_x509_construct_certificate(cert, cert_size,
145 : (uint8_t **)&x509_ca_cert);
146 6 : if ((x509_ca_cert == NULL) || (!result)) {
147 0 : return false;
148 : }
149 :
150 6 : if (pqc_asym_algo != 0) {
151 0 : result = libspdm_pqc_asym_get_private_key_from_pem(
152 : pqc_asym_algo, prikey, prikey_size, NULL, &context);
153 : } else {
154 6 : result = libspdm_asym_get_private_key_from_pem(
155 : base_asym_algo, prikey, prikey_size, NULL, &context);
156 : }
157 6 : if (!result) {
158 0 : libspdm_zero_mem(prikey, prikey_size);
159 0 : free(prikey);
160 0 : libspdm_x509_free(x509_ca_cert);
161 0 : return false;
162 : }
163 6 : hash_nid = libspdm_get_hash_nid(base_hash_algo);
164 6 : asym_nid = libspdm_get_aysm_nid(base_asym_algo);
165 6 : pqc_asym_nid = libspdm_get_pqc_aysm_nid(pqc_asym_algo);
166 :
167 6 : char *subject_name = "C=NL,O=PolarSSL,CN=PolarSSL Server 1";
168 :
169 6 : result = libspdm_gen_x509_csr(hash_nid, asym_nid, pqc_asym_nid,
170 : requester_info, requester_info_length,
171 6 : !is_device_cert_model,
172 : context, subject_name,
173 : csr_len, csr_pointer,
174 6 : x509_ca_cert);
175 6 : if (pqc_asym_algo != 0) {
176 0 : libspdm_pqc_asym_free(pqc_asym_algo, context);
177 : } else {
178 6 : libspdm_asym_free(base_asym_algo, context);
179 : }
180 6 : libspdm_zero_mem(prikey, prikey_size);
181 6 : free(prikey);
182 6 : free(cert);
183 6 : libspdm_x509_free(x509_ca_cert);
184 : } else {
185 : #endif
186 : void *x509_ca_cert;
187 : void *cert;
188 : size_t cert_size;
189 :
190 0 : if (pqc_asym_algo != 0) {
191 0 : result = libspdm_get_responder_pqc_private_key_from_raw_data(pqc_asym_algo, &context);
192 : } else {
193 0 : result = libspdm_get_responder_private_key_from_raw_data(base_asym_algo, &context);
194 : }
195 0 : if (!result) {
196 0 : return false;
197 : }
198 :
199 0 : if (pqc_asym_algo != 0) {
200 0 : result = libspdm_read_responder_pqc_certificate(
201 : pqc_asym_algo, &cert, &cert_size);
202 : } else {
203 0 : result = libspdm_read_responder_certificate(
204 : base_asym_algo, &cert, &cert_size);
205 : }
206 0 : if (!result) {
207 0 : return false;
208 : }
209 :
210 0 : result = libspdm_x509_construct_certificate(cert, cert_size,
211 : (uint8_t **)&x509_ca_cert);
212 0 : if ((x509_ca_cert == NULL) || (!result)) {
213 0 : return false;
214 : }
215 :
216 0 : hash_nid = libspdm_get_hash_nid(base_hash_algo);
217 0 : asym_nid = libspdm_get_aysm_nid(base_asym_algo);
218 0 : pqc_asym_nid = libspdm_get_pqc_aysm_nid(pqc_asym_algo);
219 :
220 0 : char *subject_name = "C=NL,O=PolarSSL,CN=PolarSSL Server 1";
221 :
222 0 : result = libspdm_gen_x509_csr(hash_nid, asym_nid, pqc_asym_nid,
223 : requester_info, requester_info_length,
224 0 : !is_device_cert_model,
225 : context, subject_name,
226 : csr_len, csr_pointer,
227 0 : x509_ca_cert);
228 0 : if (pqc_asym_algo != 0) {
229 0 : libspdm_pqc_asym_free(pqc_asym_algo, context);
230 : } else {
231 0 : libspdm_asym_free(base_asym_algo, context);
232 : }
233 0 : libspdm_x509_free(x509_ca_cert);
234 0 : free(cert);
235 : #if !LIBSPDM_PRIVATE_KEY_MODE_RAW_KEY_ONLY
236 : }
237 : #endif
238 :
239 6 : if (csr_buffer_size < *csr_len) {
240 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"csr buffer is too small to store generated csr! \n"));
241 0 : result = false;
242 : }
243 6 : return result;
244 : }
245 :
246 25 : bool libspdm_gen_csr(
247 : void *spdm_context,
248 : uint32_t base_hash_algo, uint32_t base_asym_algo, uint32_t pqc_asym_algo,
249 : bool *need_reset,
250 : const void *request, size_t request_size,
251 : uint8_t *requester_info, size_t requester_info_length,
252 : uint8_t *opaque_data, uint16_t opaque_data_length,
253 : size_t *csr_len, uint8_t *csr_pointer,
254 : uint8_t req_cert_model,
255 : uint8_t *req_csr_tracking_tag,
256 : uint8_t req_key_pair_id,
257 : bool overwrite,
258 : bool *is_busy, bool *unexpected_request)
259 : {
260 : bool result;
261 : uint8_t *cached_last_csr_request;
262 : size_t cached_last_request_len;
263 : uint8_t *cached_csr;
264 : size_t csr_buffer_size;
265 : uint8_t rsp_csr_tracking_tag;
266 : uint8_t available_csr_tracking_tag;
267 : uint8_t *request_change;
268 : uint8_t index;
269 : bool flag;
270 : bool is_device_cert_model;
271 :
272 25 : is_device_cert_model =
273 : (req_cert_model == SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT);
274 25 : csr_buffer_size = *csr_len;
275 :
276 : /* Pre-1.3 connections do not carry a CSRTrackingTag (req_csr_tracking_tag is
277 : * NULL). Use the original single fixed-tag reset semantics so that the SPDM
278 : * 1.2 behavior is preserved exactly. */
279 25 : if (req_csr_tracking_tag == NULL) {
280 : /*device gen csr need reset*/
281 10 : if (*need_reset) {
282 4 : result = libspdm_read_cached_last_csr_request(&cached_last_csr_request,
283 : &cached_last_request_len,
284 : 1, &rsp_csr_tracking_tag);
285 :
286 : /*get the cached last csr request and csr*/
287 4 : if ((result) &&
288 5 : (cached_last_request_len == request_size) &&
289 2 : (libspdm_consttime_is_mem_equal(cached_last_csr_request, request,
290 2 : request_size)) &&
291 2 : (libspdm_read_cached_csr(&cached_csr, csr_len)) &&
292 1 : (*csr_len != 0)) {
293 :
294 : /*get and save cached csr*/
295 1 : if (csr_buffer_size < *csr_len) {
296 0 : free(cached_csr);
297 0 : free(cached_last_csr_request);
298 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
299 : "csr buffer is too small to store cached csr! \n"));
300 0 : return false;
301 : } else {
302 1 : libspdm_copy_mem(csr_pointer, csr_buffer_size, cached_csr, *csr_len);
303 : }
304 :
305 : /*device don't need reset this time*/
306 1 : *need_reset = false;
307 :
308 1 : free(cached_csr);
309 1 : free(cached_last_csr_request);
310 1 : return true;
311 : } else {
312 3 : if (cached_last_csr_request != NULL) {
313 2 : free(cached_last_csr_request);
314 : }
315 :
316 : /*device need reset this time: cache the last_csr_request */
317 3 : result = libspdm_cache_last_csr_request(request, request_size, 1);
318 3 : if (!result) {
319 0 : return result;
320 : }
321 :
322 : /*device need reset this time*/
323 3 : *need_reset = true;
324 3 : return true;
325 : }
326 : } else {
327 6 : result = libspdm_gen_csr_without_reset(base_hash_algo, base_asym_algo, 0,
328 : requester_info, requester_info_length,
329 : opaque_data, opaque_data_length,
330 : csr_len, csr_pointer, is_device_cert_model);
331 6 : return result;
332 : }
333 : }
334 :
335 : /* SPDM 1.3 and higher: CSRTrackingTag based reset semantics. */
336 15 : available_csr_tracking_tag = 0;
337 :
338 : /*device gen csr need reset*/
339 15 : if (*need_reset) {
340 15 : result = libspdm_read_cached_last_csr_request(&cached_last_csr_request,
341 : &cached_last_request_len,
342 15 : *req_csr_tracking_tag,
343 : &rsp_csr_tracking_tag);
344 :
345 48 : for (index = 1; index <= SPDM_MAX_CSR_TRACKING_TAG; index++) {
346 47 : if (((rsp_csr_tracking_tag >> index) & 0x01) == 0x01) {
347 14 : available_csr_tracking_tag = index;
348 14 : break;
349 : }
350 : }
351 :
352 15 : if (*req_csr_tracking_tag == 0) {
353 11 : if (available_csr_tracking_tag == 0) {
354 : /*no available tracking tag*/
355 1 : *is_busy = true;
356 1 : return false;
357 : } else {
358 10 : flag = false;
359 : }
360 : } else {
361 : /*matched csr_tracking_tag*/
362 4 : if (((rsp_csr_tracking_tag >> *req_csr_tracking_tag) & 0x01) == 0) {
363 2 : flag = true;
364 : } else {
365 : /*unexpected*/
366 2 : return false;
367 : }
368 : }
369 :
370 : /*get the cached last csr request and csr*/
371 12 : if ((result) &&
372 4 : (cached_last_request_len == request_size) &&
373 2 : (libspdm_consttime_is_mem_equal(cached_last_csr_request, request,
374 2 : request_size)) &&
375 2 : (libspdm_read_cached_csr(&cached_csr, csr_len)) &&
376 1 : (*csr_len != 0) &&
377 : (flag)) {
378 :
379 : /*get and save cached csr*/
380 1 : if (csr_buffer_size < *csr_len) {
381 0 : free(cached_csr);
382 0 : free(cached_last_csr_request);
383 0 : LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,
384 : "csr buffer is too small to store cached csr! \n"));
385 0 : return false;
386 : } else {
387 1 : libspdm_copy_mem(csr_pointer, csr_buffer_size, cached_csr, *csr_len);
388 : }
389 :
390 : /*device don't need reset this time*/
391 1 : *need_reset = false;
392 :
393 1 : free(cached_csr);
394 1 : free(cached_last_csr_request);
395 1 : return true;
396 : } else {
397 11 : if (cached_last_csr_request != NULL) {
398 1 : free(cached_last_csr_request);
399 : }
400 :
401 11 : if ((*req_csr_tracking_tag == 0) && (available_csr_tracking_tag != 0)) {
402 10 : request_change = malloc(request_size);
403 10 : libspdm_copy_mem(request_change, request_size, request,request_size);
404 :
405 10 : if (overwrite) {
406 1 : available_csr_tracking_tag = 1;
407 : /*discard all previously generated CSRTrackingTags. */
408 1 : result = libspdm_discard_all_cached_last_request();
409 1 : if (!result) {
410 0 : free(request_change);
411 0 : return result;
412 : }
413 : }
414 :
415 10 : request_change[3] |=
416 : (available_csr_tracking_tag <<
417 : SPDM_GET_CSR_REQUEST_ATTRIBUTES_CSR_TRACKING_TAG_OFFSET);
418 :
419 : /*device need reset this time: cache the last_csr_request */
420 10 : result = libspdm_cache_last_csr_request(request_change,
421 : request_size, available_csr_tracking_tag);
422 10 : if (!result) {
423 0 : free(request_change);
424 0 : return result;
425 : }
426 :
427 : /*device need reset this time*/
428 10 : *need_reset = true;
429 10 : *req_csr_tracking_tag = available_csr_tracking_tag;
430 10 : free(request_change);
431 10 : return true;
432 : } else {
433 : /*the device is busy*/
434 1 : *is_busy = true;
435 1 : return false;
436 : }
437 : }
438 : } else {
439 0 : result = libspdm_gen_csr_without_reset(base_hash_algo, base_asym_algo, pqc_asym_algo,
440 : requester_info, requester_info_length,
441 : opaque_data, opaque_data_length,
442 : csr_len, csr_pointer, is_device_cert_model);
443 0 : return result;
444 : }
445 : }
446 :
447 : #endif /* LIBSPDM_ENABLE_CAPABILITY_CSR_CAP */
|