blob: 64ac675023649a8d502da1f6b84b48a748483341 [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
143static void add_issuer_claim(struct dpe_cert_encode_ctx *me,
144 const struct layer_context_t *parent_layer_ctx)
145{
146
147 char cdi_id_hex[ID_HEX_SIZE];
148
149 convert_to_ascii_hex(&parent_layer_ctx->data.cdi_id[0],
150 sizeof(parent_layer_ctx->data.cdi_id),
151 &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
352
353dpe_error_t encode_layer_certificate(uint16_t layer_idx,
354 struct layer_context_t *layer_ctx,
355 const struct layer_context_t *parent_layer_ctx)
356{
357 dpe_error_t err;
358 struct dpe_cert_encode_ctx dpe_cert_ctx;
359 UsefulBuf cert;
360 UsefulBufC completed_cert;
361
Maulik Patele6adc112023-08-18 14:21:51 +0100362 //TODO: Update required below:
363 // For the RoT layer, certificate is signed by IAK
Maulik Patel2358bbb2023-07-21 10:56:56 +0100364 psa_key_id_t attest_key_id = parent_layer_ctx->data.attest_key_id;
365
366 /* Get started creating the certificate/token. This sets up the CBOR and
367 * COSE contexts which causes the COSE headers to be constructed.
368 */
369 cert.ptr = &layer_ctx->data.cert_buf[0];
370 cert.len = sizeof(layer_ctx->data.cert_buf);
371
372 err = certificate_encode_start(&dpe_cert_ctx,
373 cert,
374 attest_key_id);
375 if (err != DPE_NO_ERROR) {
376 return err;
377 }
378
379 /* Add all the required claims */
380 /* Add issuer/authority claim */
381 add_issuer_claim(&dpe_cert_ctx, parent_layer_ctx);
382
383 /* Add subject claim */
384 add_subject_claim(&dpe_cert_ctx, layer_ctx);
385
386 /* Encode all firmware measurements for the components linked to this layer */
387 //TODO:
388 /* It is not yet defined in the open-dice profile how to represent
389 * multiple SW components in a single certificate; In current implementation,
390 * an array is created for all the components' measurements and within the
391 * array, there are multiple maps, one for each SW component
392 */
393 encode_layer_sw_components_array(layer_idx, &dpe_cert_ctx);
394
Maulik Patele6adc112023-08-18 14:21:51 +0100395 /* Add label claim */
396 add_label_claim(&dpe_cert_ctx,
397 &layer_ctx->data.attest_key_label[0],
398 layer_ctx->data.attest_key_label_len);
399
Maulik Patel2358bbb2023-07-21 10:56:56 +0100400 /* Add public key claim */
Maulik Patele6adc112023-08-18 14:21:51 +0100401 add_public_key_claim(&dpe_cert_ctx,
402 &layer_ctx->data.attest_pub_key[0],
403 layer_ctx->data.attest_pub_key_len);
Maulik Patel2358bbb2023-07-21 10:56:56 +0100404
405 /* Add key usage claim */
406 add_key_usage_claim(&dpe_cert_ctx);
407
408 /* Finish up creating the token. This is where the actual signature
409 * is generated. This finishes up the CBOR encoding too.
410 */
411 err = certificate_encode_finish(&dpe_cert_ctx, &completed_cert);
412 if (err != DPE_NO_ERROR) {
413 return err;
414 }
415
416 /* Update the final size of the token/certificate */
417 layer_ctx->data.cert_buf_len = completed_cert.len;
418
419 return err;
420}
421
422dpe_error_t store_layer_certificate(struct layer_context_t *layer_ctx)
423{
424 //TODO:
425 (void)layer_ctx;
426 return DPE_NO_ERROR;
427}
Maulik Patele6adc112023-08-18 14:21:51 +0100428
429static void open_certificate_chain(struct dpe_cert_encode_ctx *me,
430 uint8_t *cert_chain_buf,
431 size_t cert_chain_buf_size)
432{
433 /* Set up encoding context with output buffer. */
434 QCBOREncode_Init(&me->cbor_enc_ctx,
435 (UsefulBuf){ &cert_chain_buf[0],
436 cert_chain_buf_size });
437 QCBOREncode_OpenArray(&me->cbor_enc_ctx);
438}
439
440static void add_certificate_to_chain(struct dpe_cert_encode_ctx *me,
441 struct layer_context_t *layer_ctx)
442{
443 /* Add already encoded layers certificate to the chain */
444 QCBOREncode_AddEncoded(&me->cbor_enc_ctx,
445 (UsefulBufC){ &layer_ctx->data.cert_buf[0],
446 layer_ctx->data.cert_buf_len });
447}
448
449static dpe_error_t close_certificate_chain(struct dpe_cert_encode_ctx *me,
450 size_t *cert_chain_actual_size)
451{
452 QCBORError encode_error;
453 UsefulBufC completed_cert_chain;
454
455 QCBOREncode_CloseArray(&me->cbor_enc_ctx);
456
457 encode_error = QCBOREncode_Finish(&me->cbor_enc_ctx,
458 &completed_cert_chain);
459
460 /* Check for any encoding errors. */
461 if (encode_error == QCBOR_ERR_BUFFER_TOO_SMALL) {
462 return DPE_INSUFFICIENT_MEMORY;
463 } else if (encode_error != QCBOR_SUCCESS) {
464 return DPE_INTERNAL_ERROR;
465 }
466
467 *cert_chain_actual_size = completed_cert_chain.len;
468
469 return DPE_NO_ERROR;
470}
471
472static dpe_error_t add_root_attestation_public_key(struct dpe_cert_encode_ctx *me)
473{
474 psa_status_t status;
475 psa_key_id_t attest_key_id;
476 uint8_t attest_pub_key[DPE_ATTEST_PUB_KEY_SIZE];
477 size_t attest_pub_key_len;
478
479 attest_key_id = dpe_plat_get_root_attest_key_id();
480
481 status = psa_export_public_key(attest_key_id, attest_pub_key,
482 sizeof(attest_pub_key), &attest_pub_key_len);
483 if (status != PSA_SUCCESS) {
484 return DPE_INTERNAL_ERROR;
485 }
486
487 add_public_key_to_certificate_chain(me, &attest_pub_key[0], attest_pub_key_len);
488
489 return DPE_NO_ERROR;
490}
491
492dpe_error_t get_certificate_chain(uint16_t layer_idx,
493 uint8_t *cert_chain_buf,
494 size_t cert_chain_buf_size,
495 size_t *cert_chain_actual_size)
496{
497 struct layer_context_t *layer_ctx;
498 struct dpe_cert_encode_ctx dpe_cert_chain_ctx;
499 dpe_error_t err;
500 int i;
501 uint16_t layer_chain[MAX_NUM_OF_LAYERS];
502 uint16_t layer_cnt = 0;
503
504 open_certificate_chain(&dpe_cert_chain_ctx,
505 cert_chain_buf,
506 cert_chain_buf_size);
507
508 /* Add DICE/Root public key (IAK public key) as the first entry of array */
509 err = add_root_attestation_public_key(&dpe_cert_chain_ctx);
510 if (err != DPE_NO_ERROR) {
511 return err;
512 }
513
514 /* Loop from leaf to the RoT layer & save all the linked layers in this chain */
515 while ((layer_idx >= DPE_ROT_LAYER_IDX) && (layer_cnt < MAX_NUM_OF_LAYERS)) {
516
517 /* Save layer idx */
518 layer_chain[layer_cnt++] = layer_idx;
519
520 if (layer_idx == DPE_ROT_LAYER_IDX) {
521 /* This is the end of chain */
522 break;
523 }
524
525 layer_ctx = get_layer_ctx_ptr(layer_idx);
526 assert(layer_ctx->parent_layer_idx < layer_idx);
527 /* Move to the parent layer */
528 layer_idx = layer_ctx->parent_layer_idx;
529 }
530
531 i = (layer_cnt > 0) ? layer_cnt - 1 : 0;
532
533 /* Add certificate from RoT to leaf layer order */
534 while (i >= DPE_ROT_LAYER_IDX) {
535 layer_ctx = get_layer_ctx_ptr(layer_chain[i]);
536 assert(layer_ctx != NULL);
537 add_certificate_to_chain(&dpe_cert_chain_ctx, layer_ctx);
538 i--;
539 }
540
541 return close_certificate_chain(&dpe_cert_chain_ctx,
542 cert_chain_actual_size);
543}
544