blob: 2564f5a62dc36a467a3fca8f8fb95ed218f2e1e1 [file] [log] [blame]
Maulik Patel2358bbb2023-07-21 10:56:56 +01001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <assert.h>
9#include "dpe_certificate.h"
10#include "dpe_context_mngr.h"
11#include "dpe_crypto_config.h"
12#include "dpe_crypto_interface.h"
Maulik Patele6adc112023-08-18 14:21:51 +010013#include "dpe_plat.h"
Maulik Patel2358bbb2023-07-21 10:56:56 +010014#include "qcbor/qcbor_encode.h"
15#include "t_cose_common.h"
16#include "t_cose_sign1_sign.h"
17
18#define ID_HEX_SIZE (2 * DICE_ID_SIZE) /* Size of CDI encoded to ascii hex */
Maulik Patele6adc112023-08-18 14:21:51 +010019#define LABEL_HEX_SIZE (2 * DPE_EXTERNAL_LABEL_MAX_SIZE)
Maulik Patel2358bbb2023-07-21 10:56:56 +010020
21struct dpe_cert_encode_ctx {
22 QCBOREncodeContext cbor_enc_ctx;
23 struct t_cose_sign1_sign_ctx signer_ctx;
24};
25
26static void convert_to_ascii_hex(const uint8_t *in,
27 size_t in_size,
28 char *out,
29 size_t out_size)
30{
31 const char hex_table[] = "0123456789abcdef";
32 size_t in_pos = 0;
33 size_t out_pos = 0;
34
35 for (in_pos = 0; in_pos < in_size && out_pos < out_size; in_pos++) {
36 out[out_pos++] = hex_table[(in[in_pos] & 0xF0 >> 4)];
37 out[out_pos++] = hex_table[in[in_pos] & 0x0F];
38 }
39}
40
41static dpe_error_t t_cose_err_to_dpe_err(enum t_cose_err_t err)
42{
43 switch(err) {
44
45 case T_COSE_SUCCESS:
46 return DPE_NO_ERROR;
47
48 case T_COSE_ERR_TOO_SMALL:
49 return DPE_INSUFFICIENT_MEMORY;
50
51 default:
52 /* A lot of the errors are not mapped because they are
53 * primarily internal errors that should never happen. They
54 * end up here.
55 */
56 return DPE_INTERNAL_ERROR;
57 }
58}
59
60static dpe_error_t certificate_encode_start(struct dpe_cert_encode_ctx *me,
61 const UsefulBuf out_buf,
62 psa_key_handle_t private_key)
63{
64 enum t_cose_err_t t_cose_err;
65 struct t_cose_key attest_key;
66 UsefulBufC attest_key_id = {NULL, 0};
67
68 /* DPE Certificate is untagged COSE_Sign1 message */
69 t_cose_sign1_sign_init(&(me->signer_ctx), T_COSE_OPT_OMIT_CBOR_TAG, DPE_T_COSE_ALG);
70
71 attest_key.crypto_lib = T_COSE_CRYPTO_LIB_PSA;
72 attest_key.k.key_handle = private_key;
73
74 t_cose_sign1_set_signing_key(&(me->signer_ctx),
75 attest_key,
76 attest_key_id);
77
78 /* Spin up the CBOR encoder */
79 QCBOREncode_Init(&(me->cbor_enc_ctx), out_buf);
80
81 /* This will cause the cose headers to be encoded and written into
82 * out_buf using me->cbor_enc_ctx
83 */
84 t_cose_err = t_cose_sign1_encode_parameters(&(me->signer_ctx),
85 &(me->cbor_enc_ctx));
86 if (t_cose_err) {
87 return t_cose_err_to_dpe_err(t_cose_err);
88 }
89
90 QCBOREncode_OpenMap(&(me->cbor_enc_ctx));
91
92 return DPE_NO_ERROR;
93}
94
95static void add_key_usage_claim(struct dpe_cert_encode_ctx *me)
96{
97 uint8_t key_usage = DPE_CERT_KEY_USAGE_CERT_SIGN;
98
99 /* Encode key usage as byte string */
100 QCBOREncode_AddBytesToMapN(&me->cbor_enc_ctx,
101 DPE_CERT_LABEL_KEY_USAGE,
102 (UsefulBufC){ &key_usage,
103 sizeof(key_usage) });
104}
105
Maulik Patele6adc112023-08-18 14:21:51 +0100106static void add_label_claim(struct dpe_cert_encode_ctx *me,
107 const uint8_t *label,
108 size_t label_size)
109{
110 char label_hex[LABEL_HEX_SIZE];
111
112 /* If label is supplied, add label claim, else skip */
113 if ((label != NULL) && (label_size != 0)) {
114 convert_to_ascii_hex(&label[0],
115 label_size,
116 &label_hex[0],
117 sizeof(label_hex));
118
119 /* Encode label as text string */
120 QCBOREncode_AddTextToMapN(&me->cbor_enc_ctx,
121 DPE_CERT_LABEL_EXTERNAL_LABEL,
122 (UsefulBufC){ &label_hex[0],
123 label_size });
124 }
125}
126
Maulik Patel2358bbb2023-07-21 10:56:56 +0100127static void add_subject_claim(struct dpe_cert_encode_ctx *me,
128 struct layer_context_t *layer_ctx)
129{
130 char cdi_id_hex[ID_HEX_SIZE];
131
132 convert_to_ascii_hex(&layer_ctx->data.cdi_id[0],
133 sizeof(layer_ctx->data.cdi_id),
134 &cdi_id_hex[0],
135 sizeof(cdi_id_hex));
136 /* Encode subject as text string */
137 QCBOREncode_AddTextToMapN(&me->cbor_enc_ctx,
138 DPE_CERT_LABEL_SUBJECT,
139 (UsefulBufC){ &cdi_id_hex[0],
140 sizeof(cdi_id_hex) });
141}
142
Jamie Fox93225232023-09-22 14:09:30 +0100143static void encode_issuer_claim(struct dpe_cert_encode_ctx *me,
144 const uint8_t *issuer,
145 size_t issuer_size)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100146{
Maulik Patel2358bbb2023-07-21 10:56:56 +0100147 char cdi_id_hex[ID_HEX_SIZE];
148
Jamie Fox93225232023-09-22 14:09:30 +0100149 convert_to_ascii_hex(issuer,
150 issuer_size,
Maulik Patel2358bbb2023-07-21 10:56:56 +0100151 &cdi_id_hex[0],
152 sizeof(cdi_id_hex));
153
154 /* Encode issuer as text string */
155 QCBOREncode_AddTextToMapN(&me->cbor_enc_ctx,
156 DPE_CERT_LABEL_ISSUER,
157 (UsefulBufC){ &cdi_id_hex[0],
158 sizeof(cdi_id_hex) });
159}
160
Maulik Patele6adc112023-08-18 14:21:51 +0100161static void encode_public_key(struct dpe_cert_encode_ctx *me,
162 const uint8_t *pub_key,
163 size_t pub_key_size)
Maulik Patel2358bbb2023-07-21 10:56:56 +0100164{
165 /* As per RFC8152 */
166 const int64_t cose_key_type_value = DPE_T_COSE_KEY_TYPE_VAL;
167 const int64_t cose_key_ops_value = DPE_T_COSE_KEY_OPS_VAL;
168 const int64_t cose_key_ec2_curve_value = DPE_T_COSE_KEY_EC2_CURVE_VAL;
169 const int64_t cose_key_alg_value = DPE_T_COSE_KEY_ALG_VAL;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100170
Maulik Patel2358bbb2023-07-21 10:56:56 +0100171 QCBOREncode_OpenMap(&me->cbor_enc_ctx);
172
173 /* Add the key type as int */
174 QCBOREncode_AddInt64ToMapN(&me->cbor_enc_ctx,
175 DPE_CERT_LABEL_COSE_KEY_TYPE,
176 cose_key_type_value);
177
178 /* Add the algorithm as int */
179 QCBOREncode_AddInt64ToMapN(&me->cbor_enc_ctx,
180 DPE_CERT_LABEL_COSE_KEY_ALG,
181 cose_key_alg_value);
182
183 /* Add the key operation as [+ (tstr/int)] */
184 QCBOREncode_OpenArrayInMapN(&me->cbor_enc_ctx, DPE_CERT_LABEL_COSE_KEY_OPS);
185 QCBOREncode_AddInt64(&me->cbor_enc_ctx,
186 cose_key_ops_value);
187 QCBOREncode_CloseArray(&me->cbor_enc_ctx);
188
189 /* Add the curve */
190 QCBOREncode_AddInt64ToMapN(&me->cbor_enc_ctx,
191 DPE_CERT_LABEL_COSE_KEY_EC2_CURVE,
192 cose_key_ec2_curve_value);
193
194 /* Add the subject public key x and y coordinates */
195 QCBOREncode_AddBytesToMapN(&me->cbor_enc_ctx,
196 DPE_CERT_LABEL_COSE_KEY_EC2_X,
Maulik Patele6adc112023-08-18 14:21:51 +0100197 (UsefulBufC){ &pub_key[0],
198 pub_key_size / 2 });
Maulik Patel2358bbb2023-07-21 10:56:56 +0100199
200 QCBOREncode_AddBytesToMapN(&me->cbor_enc_ctx,
201 DPE_CERT_LABEL_COSE_KEY_EC2_Y,
Maulik Patele6adc112023-08-18 14:21:51 +0100202 (UsefulBufC){ &pub_key[pub_key_size / 2],
203 pub_key_size / 2 });
Maulik Patel2358bbb2023-07-21 10:56:56 +0100204
205 QCBOREncode_CloseMap(&me->cbor_enc_ctx);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100206
Maulik Patele6adc112023-08-18 14:21:51 +0100207}
208
209static void add_public_key_claim(struct dpe_cert_encode_ctx *me,
210 const uint8_t *pub_key,
211 size_t pub_key_size)
212{
213 UsefulBufC wrapped;
214
215 /* Cose key is encoded as a map. This map is wrapped into the a
216 * byte string and it is further encoded as a map */
217 QCBOREncode_BstrWrapInMapN(&me->cbor_enc_ctx, DPE_CERT_LABEL_SUBJECT_PUBLIC_KEY);
218 encode_public_key(me, pub_key, pub_key_size);
219 QCBOREncode_CloseBstrWrap2(&me->cbor_enc_ctx, true, &wrapped);
220 assert(wrapped.len <= DICE_MAX_ENCODED_PUBLIC_KEY_SIZE);
221}
222
223static void add_public_key_to_certificate_chain(struct dpe_cert_encode_ctx *me,
224 const uint8_t *pub_key,
225 size_t pub_key_size)
226{
227 UsefulBufC wrapped;
228
229 /* Cose key is encoded as a map wrapped into a byte string */
230 QCBOREncode_BstrWrap(&me->cbor_enc_ctx);
231 encode_public_key(me, pub_key, pub_key_size);
232 QCBOREncode_CloseBstrWrap2(&me->cbor_enc_ctx, true, &wrapped);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100233 assert(wrapped.len <= DICE_MAX_ENCODED_PUBLIC_KEY_SIZE);
234}
235
236static dpe_error_t certificate_encode_finish(struct dpe_cert_encode_ctx *me,
237 UsefulBufC *completed_cert)
238{
239 QCBORError qcbor_result;
240 enum t_cose_err_t cose_return_value;
241
242 QCBOREncode_CloseMap(&(me->cbor_enc_ctx));
243
244 /* -- Finish up the COSE_Sign1. This is where the signing happens -- */
245 cose_return_value = t_cose_sign1_encode_signature(&(me->signer_ctx),
246 &(me->cbor_enc_ctx));
247 if (cose_return_value) {
248 /* Main errors are invoking the hash or signature */
249 return t_cose_err_to_dpe_err(cose_return_value);
250 }
251
252 /* Finally close off the CBOR formatting and get the pointer and length
253 * of the resulting COSE_Sign1
254 */
255 qcbor_result = QCBOREncode_Finish(&(me->cbor_enc_ctx), completed_cert);
256 if (qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) {
257 return DPE_INSUFFICIENT_MEMORY;
258
259 } else if (qcbor_result != QCBOR_SUCCESS) {
260 /* likely from array not closed, too many closes, ... */
261 return DPE_INTERNAL_ERROR;
262
263 } else {
264 return DPE_NO_ERROR;
265 }
266}
267
268static void encode_sw_component_measurements(QCBOREncodeContext *encode_ctx,
269 struct component_context_t *component_ctx)
270{
271 QCBOREncode_OpenMap(encode_ctx);
272
273 /* Encode measurement value as byte string */
274 QCBOREncode_AddBytesToMapN(encode_ctx,
275 DPE_CERT_LABEL_CODE_HASH,
276 (UsefulBufC){ &component_ctx->data.measurement_value,
277 DICE_HASH_SIZE });
278
279 /* Encode measurement descriptor version as byte string */
280 QCBOREncode_AddBytesToMapN(encode_ctx,
281 DPE_CERT_LABEL_CODE_DESCRIPTOR,
282 (UsefulBufC){ &component_ctx->data.measurement_descriptor,
283 component_ctx->data.measurement_descriptor_size });
284
285 /* Encode signer ID Hash as byte string */
286 QCBOREncode_AddBytesToMapN(encode_ctx,
287 DPE_CERT_LABEL_AUTHORITY_HASH,
288 (UsefulBufC){ &component_ctx->data.signer_id,
289 DICE_HASH_SIZE });
290
291 /* Encode signer ID descriptor as byte string */
292 QCBOREncode_AddBytesToMapN(encode_ctx,
293 DPE_CERT_LABEL_AUTHORITY_DESCRIPTOR,
294 (UsefulBufC){ &component_ctx->data.signer_id_descriptor,
295 component_ctx->data.signer_id_descriptor_size });
296
297 if (component_ctx->data.config_descriptor_size > 0) {
298 /* Encode config descriptor as byte string */
299 QCBOREncode_AddBytesToMapN(encode_ctx,
300 DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
301 (UsefulBufC){ &component_ctx->data.config_descriptor,
302 component_ctx->data.config_descriptor_size });
303 /* Encode config value as byte string */
304 QCBOREncode_AddBytesToMapN(encode_ctx,
305 DPE_CERT_LABEL_CONFIGURATION_HASH,
306 (UsefulBufC){ &component_ctx->data.config_value,
307 DICE_INLINE_CONFIG_SIZE });
308 } else {
309 /* Encode config value as byte string */
310 QCBOREncode_AddBytesToMapN(encode_ctx,
311 DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
312 (UsefulBufC){ &component_ctx->data.config_value,
313 DICE_INLINE_CONFIG_SIZE });
314 }
315
316 /* Encode mode value as byte string */
317 QCBOREncode_AddBytesToMapN(encode_ctx,
318 DPE_CERT_LABEL_MODE,
319 (UsefulBufC){ &component_ctx->data.mode,
320 sizeof(DiceMode) });
321
322 QCBOREncode_CloseMap(encode_ctx);
323}
324
325static void encode_layer_sw_components_array(uint16_t layer_idx,
326 struct dpe_cert_encode_ctx *me)
327{
328 int i, cnt;
329 struct component_context_t *component_ctx;
330
331 for (i = 0, cnt = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
332 component_ctx = get_component_if_linked_to_layer(layer_idx, i);
333 if (component_ctx != NULL) {
334 /* This component belongs to current layer */
335 cnt++;
336
337 if (cnt == 1) {
338 /* Open array which stores SW components claims. */
339 QCBOREncode_OpenArrayInMapN(&me->cbor_enc_ctx,
340 DPE_CERT_LABEL_SW_COMPONENTS);
341 }
342 encode_sw_component_measurements(&me->cbor_enc_ctx, component_ctx);
343 }
344 }
345
346 if (cnt != 0) {
347 /* Close array which stores SW components claims. */
348 QCBOREncode_CloseArray(&me->cbor_enc_ctx);
349 }
350}
351
Jamie Fox93225232023-09-22 14:09:30 +0100352static dpe_error_t add_issuer_claim(struct dpe_cert_encode_ctx *me,
353 uint16_t layer_idx,
354 psa_key_id_t root_attest_key_id,
355 const struct layer_context_t *parent_layer_ctx)
356{
357 uint8_t rot_cdi_id[DICE_ID_SIZE];
358
359 if (layer_idx == DPE_ROT_LAYER_IDX) {
360 /* For the RoT layer, issuer id is derived from the root attestation key */
361 if (derive_cdi_id(root_attest_key_id, rot_cdi_id,
362 sizeof(rot_cdi_id)) != PSA_SUCCESS) {
363 return DPE_INTERNAL_ERROR;
364 }
365
366 encode_issuer_claim(me,
367 rot_cdi_id,
368 sizeof(rot_cdi_id));
369 } else {
370 encode_issuer_claim(me,
371 parent_layer_ctx->data.cdi_id,
372 sizeof(parent_layer_ctx->data.cdi_id));
373 }
374
375 return DPE_NO_ERROR;
376}
Maulik Patel2358bbb2023-07-21 10:56:56 +0100377
378dpe_error_t encode_layer_certificate(uint16_t layer_idx,
379 struct layer_context_t *layer_ctx,
380 const struct layer_context_t *parent_layer_ctx)
381{
382 dpe_error_t err;
383 struct dpe_cert_encode_ctx dpe_cert_ctx;
384 UsefulBuf cert;
385 UsefulBufC completed_cert;
Jamie Fox93225232023-09-22 14:09:30 +0100386 psa_key_id_t attest_key_id;
Maulik Patel2358bbb2023-07-21 10:56:56 +0100387
Jamie Fox93225232023-09-22 14:09:30 +0100388 /* The RoT layer certificate is signed by the provisioned attestation key,
389 * all other layers are signed by the parent layer's key.
390 */
391 if (layer_idx == DPE_ROT_LAYER_IDX) {
392 attest_key_id = dpe_plat_get_root_attest_key_id();
393 } else {
394 attest_key_id = parent_layer_ctx->data.attest_key_id;
395 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100396
397 /* Get started creating the certificate/token. This sets up the CBOR and
398 * COSE contexts which causes the COSE headers to be constructed.
399 */
400 cert.ptr = &layer_ctx->data.cert_buf[0];
401 cert.len = sizeof(layer_ctx->data.cert_buf);
402
403 err = certificate_encode_start(&dpe_cert_ctx,
404 cert,
405 attest_key_id);
406 if (err != DPE_NO_ERROR) {
407 return err;
408 }
409
410 /* Add all the required claims */
411 /* Add issuer/authority claim */
Jamie Fox93225232023-09-22 14:09:30 +0100412 err = add_issuer_claim(&dpe_cert_ctx, layer_idx, attest_key_id, parent_layer_ctx);
413 if (err != DPE_NO_ERROR) {
414 return err;
415 }
Maulik Patel2358bbb2023-07-21 10:56:56 +0100416
417 /* Add subject claim */
418 add_subject_claim(&dpe_cert_ctx, layer_ctx);
419
420 /* Encode all firmware measurements for the components linked to this layer */
421 //TODO:
422 /* It is not yet defined in the open-dice profile how to represent
423 * multiple SW components in a single certificate; In current implementation,
424 * an array is created for all the components' measurements and within the
425 * array, there are multiple maps, one for each SW component
426 */
427 encode_layer_sw_components_array(layer_idx, &dpe_cert_ctx);
428
Maulik Patele6adc112023-08-18 14:21:51 +0100429 /* Add label claim */
430 add_label_claim(&dpe_cert_ctx,
431 &layer_ctx->data.attest_key_label[0],
432 layer_ctx->data.attest_key_label_len);
433
Maulik Patel2358bbb2023-07-21 10:56:56 +0100434 /* Add public key claim */
Maulik Patele6adc112023-08-18 14:21:51 +0100435 add_public_key_claim(&dpe_cert_ctx,
436 &layer_ctx->data.attest_pub_key[0],
437 layer_ctx->data.attest_pub_key_len);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100438
439 /* Add key usage claim */
440 add_key_usage_claim(&dpe_cert_ctx);
441
442 /* Finish up creating the token. This is where the actual signature
443 * is generated. This finishes up the CBOR encoding too.
444 */
445 err = certificate_encode_finish(&dpe_cert_ctx, &completed_cert);
446 if (err != DPE_NO_ERROR) {
447 return err;
448 }
449
450 /* Update the final size of the token/certificate */
451 layer_ctx->data.cert_buf_len = completed_cert.len;
452
453 return err;
454}
455
456dpe_error_t store_layer_certificate(struct layer_context_t *layer_ctx)
457{
458 //TODO:
459 (void)layer_ctx;
460 return DPE_NO_ERROR;
461}
Maulik Patele6adc112023-08-18 14:21:51 +0100462
463static void open_certificate_chain(struct dpe_cert_encode_ctx *me,
464 uint8_t *cert_chain_buf,
465 size_t cert_chain_buf_size)
466{
467 /* Set up encoding context with output buffer. */
468 QCBOREncode_Init(&me->cbor_enc_ctx,
469 (UsefulBuf){ &cert_chain_buf[0],
470 cert_chain_buf_size });
471 QCBOREncode_OpenArray(&me->cbor_enc_ctx);
472}
473
474static void add_certificate_to_chain(struct dpe_cert_encode_ctx *me,
475 struct layer_context_t *layer_ctx)
476{
477 /* Add already encoded layers certificate to the chain */
478 QCBOREncode_AddEncoded(&me->cbor_enc_ctx,
479 (UsefulBufC){ &layer_ctx->data.cert_buf[0],
480 layer_ctx->data.cert_buf_len });
481}
482
483static dpe_error_t close_certificate_chain(struct dpe_cert_encode_ctx *me,
484 size_t *cert_chain_actual_size)
485{
486 QCBORError encode_error;
487 UsefulBufC completed_cert_chain;
488
489 QCBOREncode_CloseArray(&me->cbor_enc_ctx);
490
491 encode_error = QCBOREncode_Finish(&me->cbor_enc_ctx,
492 &completed_cert_chain);
493
494 /* Check for any encoding errors. */
495 if (encode_error == QCBOR_ERR_BUFFER_TOO_SMALL) {
496 return DPE_INSUFFICIENT_MEMORY;
497 } else if (encode_error != QCBOR_SUCCESS) {
498 return DPE_INTERNAL_ERROR;
499 }
500
501 *cert_chain_actual_size = completed_cert_chain.len;
502
503 return DPE_NO_ERROR;
504}
505
506static dpe_error_t add_root_attestation_public_key(struct dpe_cert_encode_ctx *me)
507{
508 psa_status_t status;
509 psa_key_id_t attest_key_id;
510 uint8_t attest_pub_key[DPE_ATTEST_PUB_KEY_SIZE];
511 size_t attest_pub_key_len;
512
513 attest_key_id = dpe_plat_get_root_attest_key_id();
514
515 status = psa_export_public_key(attest_key_id, attest_pub_key,
516 sizeof(attest_pub_key), &attest_pub_key_len);
517 if (status != PSA_SUCCESS) {
518 return DPE_INTERNAL_ERROR;
519 }
520
521 add_public_key_to_certificate_chain(me, &attest_pub_key[0], attest_pub_key_len);
522
523 return DPE_NO_ERROR;
524}
525
526dpe_error_t get_certificate_chain(uint16_t layer_idx,
527 uint8_t *cert_chain_buf,
528 size_t cert_chain_buf_size,
529 size_t *cert_chain_actual_size)
530{
531 struct layer_context_t *layer_ctx;
532 struct dpe_cert_encode_ctx dpe_cert_chain_ctx;
533 dpe_error_t err;
534 int i;
535 uint16_t layer_chain[MAX_NUM_OF_LAYERS];
536 uint16_t layer_cnt = 0;
537
538 open_certificate_chain(&dpe_cert_chain_ctx,
539 cert_chain_buf,
540 cert_chain_buf_size);
541
542 /* Add DICE/Root public key (IAK public key) as the first entry of array */
543 err = add_root_attestation_public_key(&dpe_cert_chain_ctx);
544 if (err != DPE_NO_ERROR) {
545 return err;
546 }
547
548 /* Loop from leaf to the RoT layer & save all the linked layers in this chain */
549 while ((layer_idx >= DPE_ROT_LAYER_IDX) && (layer_cnt < MAX_NUM_OF_LAYERS)) {
550
551 /* Save layer idx */
552 layer_chain[layer_cnt++] = layer_idx;
553
554 if (layer_idx == DPE_ROT_LAYER_IDX) {
555 /* This is the end of chain */
556 break;
557 }
558
559 layer_ctx = get_layer_ctx_ptr(layer_idx);
560 assert(layer_ctx->parent_layer_idx < layer_idx);
561 /* Move to the parent layer */
562 layer_idx = layer_ctx->parent_layer_idx;
563 }
564
565 i = (layer_cnt > 0) ? layer_cnt - 1 : 0;
566
567 /* Add certificate from RoT to leaf layer order */
568 while (i >= DPE_ROT_LAYER_IDX) {
569 layer_ctx = get_layer_ctx_ptr(layer_chain[i]);
570 assert(layer_ctx != NULL);
571 add_certificate_to_chain(&dpe_cert_chain_ctx, layer_ctx);
572 i--;
573 }
574
575 return close_certificate_chain(&dpe_cert_chain_ctx,
576 cert_chain_actual_size);
577}