DPE: Create intermediate certificate for the layer
Signed-off-by: Maulik Patel <maulik.patel@arm.com>
Change-Id: Ib7df067daa3674f42bbff3b0296b7df192936caa
diff --git a/partitions/dice_protection_environment/CMakeLists.txt b/partitions/dice_protection_environment/CMakeLists.txt
index 6f2fb34..a4490d5 100644
--- a/partitions/dice_protection_environment/CMakeLists.txt
+++ b/partitions/dice_protection_environment/CMakeLists.txt
@@ -19,6 +19,7 @@
target_sources(tfm_app_rot_partition_dpe
PRIVATE
+ dpe_certificate.c
dpe_cmd_decode.c
dpe_context_mngr.c
dpe_crypto_interface.c
@@ -56,6 +57,7 @@
PRIVATE
tfm_sprt
qcbor
+ tfm_t_cose_s
)
############################ Secure API ########################################
diff --git a/partitions/dice_protection_environment/dpe_certificate.c b/partitions/dice_protection_environment/dpe_certificate.c
new file mode 100644
index 0000000..d66d599
--- /dev/null
+++ b/partitions/dice_protection_environment/dpe_certificate.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <assert.h>
+#include "dpe_certificate.h"
+#include "dpe_context_mngr.h"
+#include "dpe_crypto_config.h"
+#include "dpe_crypto_interface.h"
+#include "qcbor/qcbor_encode.h"
+#include "t_cose_common.h"
+#include "t_cose_sign1_sign.h"
+
+#define ID_HEX_SIZE (2 * DICE_ID_SIZE) /* Size of CDI encoded to ascii hex */
+
+struct dpe_cert_encode_ctx {
+ QCBOREncodeContext cbor_enc_ctx;
+ struct t_cose_sign1_sign_ctx signer_ctx;
+};
+
+static void convert_to_ascii_hex(const uint8_t *in,
+ size_t in_size,
+ char *out,
+ size_t out_size)
+{
+ const char hex_table[] = "0123456789abcdef";
+ size_t in_pos = 0;
+ size_t out_pos = 0;
+
+ for (in_pos = 0; in_pos < in_size && out_pos < out_size; in_pos++) {
+ out[out_pos++] = hex_table[(in[in_pos] & 0xF0 >> 4)];
+ out[out_pos++] = hex_table[in[in_pos] & 0x0F];
+ }
+}
+
+static dpe_error_t t_cose_err_to_dpe_err(enum t_cose_err_t err)
+{
+ switch(err) {
+
+ case T_COSE_SUCCESS:
+ return DPE_NO_ERROR;
+
+ case T_COSE_ERR_TOO_SMALL:
+ return DPE_INSUFFICIENT_MEMORY;
+
+ default:
+ /* A lot of the errors are not mapped because they are
+ * primarily internal errors that should never happen. They
+ * end up here.
+ */
+ return DPE_INTERNAL_ERROR;
+ }
+}
+
+static dpe_error_t certificate_encode_start(struct dpe_cert_encode_ctx *me,
+ const UsefulBuf out_buf,
+ psa_key_handle_t private_key)
+{
+ enum t_cose_err_t t_cose_err;
+ struct t_cose_key attest_key;
+ UsefulBufC attest_key_id = {NULL, 0};
+
+ /* DPE Certificate is untagged COSE_Sign1 message */
+ t_cose_sign1_sign_init(&(me->signer_ctx), T_COSE_OPT_OMIT_CBOR_TAG, DPE_T_COSE_ALG);
+
+ attest_key.crypto_lib = T_COSE_CRYPTO_LIB_PSA;
+ attest_key.k.key_handle = private_key;
+
+ t_cose_sign1_set_signing_key(&(me->signer_ctx),
+ attest_key,
+ attest_key_id);
+
+ /* Spin up the CBOR encoder */
+ QCBOREncode_Init(&(me->cbor_enc_ctx), out_buf);
+
+ /* This will cause the cose headers to be encoded and written into
+ * out_buf using me->cbor_enc_ctx
+ */
+ t_cose_err = t_cose_sign1_encode_parameters(&(me->signer_ctx),
+ &(me->cbor_enc_ctx));
+ if (t_cose_err) {
+ return t_cose_err_to_dpe_err(t_cose_err);
+ }
+
+ QCBOREncode_OpenMap(&(me->cbor_enc_ctx));
+
+ return DPE_NO_ERROR;
+}
+
+static void add_key_usage_claim(struct dpe_cert_encode_ctx *me)
+{
+ uint8_t key_usage = DPE_CERT_KEY_USAGE_CERT_SIGN;
+
+ /* Encode key usage as byte string */
+ QCBOREncode_AddBytesToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_KEY_USAGE,
+ (UsefulBufC){ &key_usage,
+ sizeof(key_usage) });
+}
+
+static void add_subject_claim(struct dpe_cert_encode_ctx *me,
+ struct layer_context_t *layer_ctx)
+{
+ char cdi_id_hex[ID_HEX_SIZE];
+
+ convert_to_ascii_hex(&layer_ctx->data.cdi_id[0],
+ sizeof(layer_ctx->data.cdi_id),
+ &cdi_id_hex[0],
+ sizeof(cdi_id_hex));
+ /* Encode subject as text string */
+ QCBOREncode_AddTextToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_SUBJECT,
+ (UsefulBufC){ &cdi_id_hex[0],
+ sizeof(cdi_id_hex) });
+}
+
+static void add_issuer_claim(struct dpe_cert_encode_ctx *me,
+ const struct layer_context_t *parent_layer_ctx)
+{
+
+ char cdi_id_hex[ID_HEX_SIZE];
+
+ convert_to_ascii_hex(&parent_layer_ctx->data.cdi_id[0],
+ sizeof(parent_layer_ctx->data.cdi_id),
+ &cdi_id_hex[0],
+ sizeof(cdi_id_hex));
+
+ /* Encode issuer as text string */
+ QCBOREncode_AddTextToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_ISSUER,
+ (UsefulBufC){ &cdi_id_hex[0],
+ sizeof(cdi_id_hex) });
+}
+
+static void add_public_key_claim(struct dpe_cert_encode_ctx *me,
+ const struct layer_context_t *layer_ctx)
+{
+ /* As per RFC8152 */
+ const int64_t cose_key_type_value = DPE_T_COSE_KEY_TYPE_VAL;
+ const int64_t cose_key_ops_value = DPE_T_COSE_KEY_OPS_VAL;
+ const int64_t cose_key_ec2_curve_value = DPE_T_COSE_KEY_EC2_CURVE_VAL;
+ const int64_t cose_key_alg_value = DPE_T_COSE_KEY_ALG_VAL;
+ size_t pub_key_size = layer_ctx->data.attest_pub_key_len;
+ UsefulBufC wrapped;
+
+ /* Cose key is encoded as a map wrapped into a byte string */
+ QCBOREncode_BstrWrapInMapN(&me->cbor_enc_ctx, DPE_CERT_LABEL_SUBJECT_PUBLIC_KEY);
+ QCBOREncode_OpenMap(&me->cbor_enc_ctx);
+
+ /* Add the key type as int */
+ QCBOREncode_AddInt64ToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_COSE_KEY_TYPE,
+ cose_key_type_value);
+
+ /* Add the algorithm as int */
+ QCBOREncode_AddInt64ToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_COSE_KEY_ALG,
+ cose_key_alg_value);
+
+ /* Add the key operation as [+ (tstr/int)] */
+ QCBOREncode_OpenArrayInMapN(&me->cbor_enc_ctx, DPE_CERT_LABEL_COSE_KEY_OPS);
+ QCBOREncode_AddInt64(&me->cbor_enc_ctx,
+ cose_key_ops_value);
+ QCBOREncode_CloseArray(&me->cbor_enc_ctx);
+
+ /* Add the curve */
+ QCBOREncode_AddInt64ToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_COSE_KEY_EC2_CURVE,
+ cose_key_ec2_curve_value);
+
+ /* Add the subject public key x and y coordinates */
+ QCBOREncode_AddBytesToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_COSE_KEY_EC2_X,
+ (UsefulBufC){ &layer_ctx->data.attest_pub_key[0],
+ pub_key_size/2 });
+
+ QCBOREncode_AddBytesToMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_COSE_KEY_EC2_Y,
+ (UsefulBufC){ &layer_ctx->data.attest_pub_key[pub_key_size/2],
+ pub_key_size/2 });
+
+ QCBOREncode_CloseMap(&me->cbor_enc_ctx);
+ QCBOREncode_CloseBstrWrap2(&me->cbor_enc_ctx, true, &wrapped);
+
+ assert(wrapped.len <= DICE_MAX_ENCODED_PUBLIC_KEY_SIZE);
+}
+
+static dpe_error_t certificate_encode_finish(struct dpe_cert_encode_ctx *me,
+ UsefulBufC *completed_cert)
+{
+ QCBORError qcbor_result;
+ enum t_cose_err_t cose_return_value;
+
+ QCBOREncode_CloseMap(&(me->cbor_enc_ctx));
+
+ /* -- Finish up the COSE_Sign1. This is where the signing happens -- */
+ cose_return_value = t_cose_sign1_encode_signature(&(me->signer_ctx),
+ &(me->cbor_enc_ctx));
+ if (cose_return_value) {
+ /* Main errors are invoking the hash or signature */
+ return t_cose_err_to_dpe_err(cose_return_value);
+ }
+
+ /* Finally close off the CBOR formatting and get the pointer and length
+ * of the resulting COSE_Sign1
+ */
+ qcbor_result = QCBOREncode_Finish(&(me->cbor_enc_ctx), completed_cert);
+ if (qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) {
+ return DPE_INSUFFICIENT_MEMORY;
+
+ } else if (qcbor_result != QCBOR_SUCCESS) {
+ /* likely from array not closed, too many closes, ... */
+ return DPE_INTERNAL_ERROR;
+
+ } else {
+ return DPE_NO_ERROR;
+ }
+}
+
+static void encode_sw_component_measurements(QCBOREncodeContext *encode_ctx,
+ struct component_context_t *component_ctx)
+{
+ QCBOREncode_OpenMap(encode_ctx);
+
+ /* Encode measurement value as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_CODE_HASH,
+ (UsefulBufC){ &component_ctx->data.measurement_value,
+ DICE_HASH_SIZE });
+
+ /* Encode measurement descriptor version as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_CODE_DESCRIPTOR,
+ (UsefulBufC){ &component_ctx->data.measurement_descriptor,
+ component_ctx->data.measurement_descriptor_size });
+
+ /* Encode signer ID Hash as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_AUTHORITY_HASH,
+ (UsefulBufC){ &component_ctx->data.signer_id,
+ DICE_HASH_SIZE });
+
+ /* Encode signer ID descriptor as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_AUTHORITY_DESCRIPTOR,
+ (UsefulBufC){ &component_ctx->data.signer_id_descriptor,
+ component_ctx->data.signer_id_descriptor_size });
+
+ if (component_ctx->data.config_descriptor_size > 0) {
+ /* Encode config descriptor as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
+ (UsefulBufC){ &component_ctx->data.config_descriptor,
+ component_ctx->data.config_descriptor_size });
+ /* Encode config value as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_CONFIGURATION_HASH,
+ (UsefulBufC){ &component_ctx->data.config_value,
+ DICE_INLINE_CONFIG_SIZE });
+ } else {
+ /* Encode config value as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR,
+ (UsefulBufC){ &component_ctx->data.config_value,
+ DICE_INLINE_CONFIG_SIZE });
+ }
+
+ /* Encode mode value as byte string */
+ QCBOREncode_AddBytesToMapN(encode_ctx,
+ DPE_CERT_LABEL_MODE,
+ (UsefulBufC){ &component_ctx->data.mode,
+ sizeof(DiceMode) });
+
+ QCBOREncode_CloseMap(encode_ctx);
+}
+
+static void encode_layer_sw_components_array(uint16_t layer_idx,
+ struct dpe_cert_encode_ctx *me)
+{
+ int i, cnt;
+ struct component_context_t *component_ctx;
+
+ for (i = 0, cnt = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
+ component_ctx = get_component_if_linked_to_layer(layer_idx, i);
+ if (component_ctx != NULL) {
+ /* This component belongs to current layer */
+ cnt++;
+
+ if (cnt == 1) {
+ /* Open array which stores SW components claims. */
+ QCBOREncode_OpenArrayInMapN(&me->cbor_enc_ctx,
+ DPE_CERT_LABEL_SW_COMPONENTS);
+ }
+ encode_sw_component_measurements(&me->cbor_enc_ctx, component_ctx);
+ }
+ }
+
+ if (cnt != 0) {
+ /* Close array which stores SW components claims. */
+ QCBOREncode_CloseArray(&me->cbor_enc_ctx);
+ }
+}
+
+
+dpe_error_t encode_layer_certificate(uint16_t layer_idx,
+ struct layer_context_t *layer_ctx,
+ const struct layer_context_t *parent_layer_ctx)
+{
+ dpe_error_t err;
+ struct dpe_cert_encode_ctx dpe_cert_ctx;
+ UsefulBuf cert;
+ UsefulBufC completed_cert;
+
+ psa_key_id_t attest_key_id = parent_layer_ctx->data.attest_key_id;
+
+ /* Get started creating the certificate/token. This sets up the CBOR and
+ * COSE contexts which causes the COSE headers to be constructed.
+ */
+ cert.ptr = &layer_ctx->data.cert_buf[0];
+ cert.len = sizeof(layer_ctx->data.cert_buf);
+
+ err = certificate_encode_start(&dpe_cert_ctx,
+ cert,
+ attest_key_id);
+ if (err != DPE_NO_ERROR) {
+ return err;
+ }
+
+ /* Add all the required claims */
+ /* Add issuer/authority claim */
+ add_issuer_claim(&dpe_cert_ctx, parent_layer_ctx);
+
+ /* Add subject claim */
+ add_subject_claim(&dpe_cert_ctx, layer_ctx);
+
+ /* Encode all firmware measurements for the components linked to this layer */
+ //TODO:
+ /* It is not yet defined in the open-dice profile how to represent
+ * multiple SW components in a single certificate; In current implementation,
+ * an array is created for all the components' measurements and within the
+ * array, there are multiple maps, one for each SW component
+ */
+ encode_layer_sw_components_array(layer_idx, &dpe_cert_ctx);
+
+ /* Add public key claim */
+ add_public_key_claim(&dpe_cert_ctx, layer_ctx);
+
+ /* Add key usage claim */
+ add_key_usage_claim(&dpe_cert_ctx);
+
+ /* Finish up creating the token. This is where the actual signature
+ * is generated. This finishes up the CBOR encoding too.
+ */
+ err = certificate_encode_finish(&dpe_cert_ctx, &completed_cert);
+ if (err != DPE_NO_ERROR) {
+ return err;
+ }
+
+ /* Update the final size of the token/certificate */
+ layer_ctx->data.cert_buf_len = completed_cert.len;
+
+ return err;
+}
+
+dpe_error_t store_layer_certificate(struct layer_context_t *layer_ctx)
+{
+ //TODO:
+ (void)layer_ctx;
+ return DPE_NO_ERROR;
+}
diff --git a/partitions/dice_protection_environment/dpe_certificate.h b/partitions/dice_protection_environment/dpe_certificate.h
new file mode 100644
index 0000000..59c2a14
--- /dev/null
+++ b/partitions/dice_protection_environment/dpe_certificate.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef __DPE_CERTIFICATE_H__
+#define __DPE_CERTIFICATE_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include "dpe_context_mngr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* As per RFC8152 */
+#define DPE_CERT_LABEL_COSE_KEY_TYPE (1)
+#define DPE_CERT_LABEL_COSE_KEY_ID (2)
+#define DPE_CERT_LABEL_COSE_KEY_ALG (3)
+#define DPE_CERT_LABEL_COSE_KEY_OPS (4)
+#define DPE_CERT_LABEL_COSE_KEY_EC2_CURVE (-1)
+#define DPE_CERT_LABEL_COSE_KEY_EC2_X (-2)
+#define DPE_CERT_LABEL_COSE_KEY_EC2_Y (-3)
+
+/* As per RFC8392 */
+#define DPE_CERT_LABEL_ISSUER (1)
+#define DPE_CERT_LABEL_SUBJECT (2)
+
+/* As per Open Profile for DICE specification */
+#define DPE_CERT_LABEL_RANGE_BASE (-4670545)
+#define DPE_CERT_LABEL_CODE_HASH (DPE_CERT_LABEL_RANGE_BASE - 0)
+#define DPE_CERT_LABEL_CODE_DESCRIPTOR (DPE_CERT_LABEL_RANGE_BASE - 1)
+#define DPE_CERT_LABEL_CONFIGURATION_HASH (DPE_CERT_LABEL_RANGE_BASE - 2)
+#define DPE_CERT_LABEL_CONFIGURATION_DESCRIPTOR (DPE_CERT_LABEL_RANGE_BASE - 3)
+#define DPE_CERT_LABEL_AUTHORITY_HASH (DPE_CERT_LABEL_RANGE_BASE - 4)
+#define DPE_CERT_LABEL_AUTHORITY_DESCRIPTOR (DPE_CERT_LABEL_RANGE_BASE - 5)
+#define DPE_CERT_LABEL_MODE (DPE_CERT_LABEL_RANGE_BASE - 6)
+#define DPE_CERT_LABEL_SUBJECT_PUBLIC_KEY (DPE_CERT_LABEL_RANGE_BASE - 7)
+#define DPE_CERT_LABEL_KEY_USAGE (DPE_CERT_LABEL_RANGE_BASE - 8)
+
+/* Below label is custom and not specified in DICE profile */
+#define DPE_CERT_LABEL_SW_COMPONENTS (DPE_CERT_LABEL_RANGE_BASE - 9)
+
+/* Key usage constant per RFC 5280 */
+#define DPE_CERT_KEY_USAGE_CERT_SIGN (1 << 5);
+
+#define DICE_MAX_ENCODED_PUBLIC_KEY_SIZE (DPE_ATTEST_PUB_KEY_SIZE + 32)
+
+/**
+ * \brief Encodes and signs the certificate for a layer
+ *
+ * \param[in] layer_idx Index of the current layer context.
+ * \param[in] layer_ctx Pointer to current layer context.
+ * \param[in] parent_layer_ctx Pointer to parent layer context.
+ *
+ * \return Returns error code of type dpe_error_t
+ */
+dpe_error_t encode_layer_certificate(uint16_t layer_idx,
+ struct layer_context_t *layer_ctx,
+ const struct layer_context_t *parent_layer_ctx);
+
+/**
+ * \brief Stores signed certificate for a layer
+ *
+ * \param[in] layer_ctx Pointer to current layer context.
+ *
+ * \return Returns error code of type dpe_error_t
+ */
+dpe_error_t store_layer_certificate(struct layer_context_t *layer_ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DPE_CERTIFICATE_H__ */
diff --git a/partitions/dice_protection_environment/dpe_context_mngr.c b/partitions/dice_protection_environment/dpe_context_mngr.c
index 0b826a8..1698c65 100644
--- a/partitions/dice_protection_environment/dpe_context_mngr.c
+++ b/partitions/dice_protection_environment/dpe_context_mngr.c
@@ -9,6 +9,7 @@
#include <assert.h>
#include <string.h>
#include "dice_protection_environment.h"
+#include "dpe_certificate.h"
#include "dpe_crypto_interface.h"
#include "dpe_log.h"
#include "psa/crypto.h"
@@ -20,6 +21,14 @@
0xA3, 0x9F, 0xDE, 0xC3, 0x35, 0x75, 0x84, 0x6E, \
0x4C, 0xB9, 0x28, 0xAC, 0x7A, 0x4E, 0X00, 0x7F \
}
+
+#define TEST_ROT_ISSUER_SEED { \
+ 0xD2, 0x90, 0x66, 0x07, 0x2A, 0x2D, 0x2A, 0x00, \
+ 0x91, 0x9D, 0xD9, 0x15, 0x14, 0xBE, 0x2D, 0xCC, \
+ 0xA3, 0x9F, 0xDE, 0xC3, 0x35, 0x75, 0x84, 0x6E, \
+ 0x4C, 0xB9, 0x28, 0xAC, 0x7A, 0x4E, 0X00, 0x7F \
+ }
+
#endif /* TFM_S_REG_TEST */
#define CONTEXT_DATA_MAX_SIZE sizeof(struct component_context_data_t)
@@ -145,7 +154,7 @@
dest_ctx->data.config_descriptor_size = dice_inputs->config_descriptor_size;
/* Calculate config value as hash of input config descriptor */
- status = psa_hash_compute(PSA_ALG_SHA_256,
+ status = psa_hash_compute(DPE_HASH_ALG,
dice_inputs->config_descriptor,
dice_inputs->config_descriptor_size,
dest_ctx->data.config_value,
@@ -276,20 +285,22 @@
return status;
}
+
static dpe_error_t derive_child_create_certificate(uint16_t layer_idx)
{
- uint16_t parent_idx;
+ uint16_t parent_layer_idx;
psa_status_t status;
+ dpe_error_t err;
assert(layer_idx < MAX_NUM_OF_LAYERS);
/* Finalise the layer */
layer_ctx_array[layer_idx].state = LAYER_STATE_FINALISED;
- /* For RoT Layer, CDI values are calculated by BL1_1 */
+ /* For RoT Layer, CDI and issuer seed values are calculated by BL1_1 */
if (layer_idx != DPE_ROT_LAYER_IDX) {
- parent_idx = layer_ctx_array[layer_idx].parent_layer_idx;
- assert(parent_idx < MAX_NUM_OF_LAYERS);
+ parent_layer_idx = layer_ctx_array[layer_idx].parent_layer_idx;
+ assert(parent_layer_idx < MAX_NUM_OF_LAYERS);
status = compute_layer_cdi_attest_input(layer_idx);
if (status != PSA_SUCCESS) {
@@ -297,7 +308,7 @@
}
status = derive_attestation_cdi(&layer_ctx_array[layer_idx],
- &layer_ctx_array[parent_idx]);
+ &layer_ctx_array[parent_layer_idx]);
if (status != PSA_SUCCESS) {
return DPE_INTERNAL_ERROR;
}
@@ -306,6 +317,9 @@
if (status != PSA_SUCCESS) {
return DPE_INTERNAL_ERROR;
}
+ } else {
+ /* There is no parent for RoT layer */
+ parent_layer_idx = 0;
}
status = derive_wrapping_key(&layer_ctx_array[layer_idx]);
@@ -318,17 +332,23 @@
return DPE_INTERNAL_ERROR;
}
- status = create_layer_certificate(&layer_ctx_array[layer_idx]);
+ status = derive_id_from_public_key(&layer_ctx_array[layer_idx]);
if (status != PSA_SUCCESS) {
return DPE_INTERNAL_ERROR;
}
- status = store_layer_certificate(&layer_ctx_array[layer_idx]);
- if (status != PSA_SUCCESS) {
- return DPE_INTERNAL_ERROR;
+ err = encode_layer_certificate(layer_idx,
+ &layer_ctx_array[layer_idx],
+ &layer_ctx_array[parent_layer_idx]);
+ if (err != DPE_NO_ERROR) {
+ return err;
}
- return DPE_NO_ERROR;
+ log_intermediate_certificate(layer_idx,
+ &layer_ctx_array[layer_idx].data.cert_buf[0],
+ layer_ctx_array[layer_idx].data.cert_buf_len);
+
+ return store_layer_certificate(&layer_ctx_array[layer_idx]);
}
static uint16_t open_new_layer(void)
@@ -342,7 +362,18 @@
}
}
- return INVALID_LAYER_IDX;
+ //TODO: There is an open issue of layer creation as described below.
+ /* This is causing extra unintended layers to open. Since each layer
+ * has some context data and certificate buffer of 3k, it is
+ * causing RAM overflow. Hence until resoluton is reached, once all
+ * layers are opened, link new compenents to the last layer.
+ * ISSUE DESCRIPTION: We derive AP_BL31 as child of AP BL2 with create_certificate
+ * as true. Hence we finalize Platform layer. Then we derive AP_SPM as child of
+ * AP BL2, but since AP BL2 is finalised, we open new layer (Hypervisor layer).
+ * Then we derive AP SPx as child of AP BL2. Again, since AP BL2 is finalised,
+ * we open new layer! Here AP SPx should belong to same layer as AP SPM.
+ */
+ return MAX_NUM_OF_LAYERS - 1;
}
static inline void link_layer(uint16_t child_layer, uint16_t parent_layer)
@@ -416,7 +447,7 @@
return true;
}
-static void assign_layer_to_context(struct component_context_t *new_ctx)
+static dpe_error_t assign_layer_to_context(struct component_context_t *new_ctx)
{
uint16_t new_layer_idx, parent_layer_idx;
@@ -428,6 +459,9 @@
if (layer_ctx_array[parent_layer_idx].state == LAYER_STATE_FINALISED) {
/* Parent comp's layer of new child is finalised; open a new layer */
new_layer_idx = open_new_layer();
+ if (new_layer_idx == INVALID_LAYER_IDX) {
+ return DPE_INTERNAL_ERROR;
+ }
/* Link this context to the new layer */
new_ctx->linked_layer_idx = new_layer_idx;
/* New layer's parent is current layer */
@@ -439,6 +473,8 @@
*/
new_ctx->linked_layer_idx = parent_layer_idx;
}
+
+ return DPE_NO_ERROR;
}
dpe_error_t derive_child_request(int input_ctx_handle,
@@ -531,8 +567,10 @@
new_ctx->parent_idx = input_child_idx;
/* Mark new child component index as in use */
new_ctx->in_use = true;
- assign_layer_to_context(new_ctx);
-
+ status = assign_layer_to_context(new_ctx);
+ if (status != DPE_NO_ERROR) {
+ return status;
+ }
} else {
/* Child not deriving any children */
/* Tag this component as a leaf */
@@ -556,8 +594,10 @@
new_ctx->parent_idx = input_parent_idx;
/* Mark new child component index as in use */
new_ctx->in_use = true;
- assign_layer_to_context(new_ctx);
-
+ status = assign_layer_to_context(new_ctx);
+ if (status != DPE_NO_ERROR) {
+ return status;
+ }
} else {
/* Parent not deriving any more children */
/* No need to return parent handle */
@@ -627,3 +667,19 @@
return DPE_NO_ERROR;
}
+
+struct component_context_t* get_component_if_linked_to_layer(uint16_t layer_idx,
+ uint16_t component_idx)
+{
+ /* Safety case */
+ if (component_idx >= MAX_NUM_OF_COMPONENTS) {
+ return NULL;
+ }
+
+ if (component_ctx_array[component_idx].linked_layer_idx == layer_idx) {
+ return &component_ctx_array[component_idx];
+ } else {
+ return NULL;
+ }
+}
+
diff --git a/partitions/dice_protection_environment/dpe_context_mngr.h b/partitions/dice_protection_environment/dpe_context_mngr.h
index 807de46..d488a50 100644
--- a/partitions/dice_protection_environment/dpe_context_mngr.h
+++ b/partitions/dice_protection_environment/dpe_context_mngr.h
@@ -18,8 +18,7 @@
extern "C" {
#endif
-#define DICE_WRAPPING_KEY_SIZE 32
-#define DICE_CERT_SIZE 1024
+#define DICE_CERT_SIZE 3072
#define INVALID_HANDLE 0xFFFFFFFF
#define INVALID_COMPONENT_IDX 0xFFFF
@@ -29,7 +28,7 @@
/* Below configuration defines are platform dependant */
#define MAX_NUM_OF_COMPONENTS 30
-#define MAX_NUM_OF_LAYERS 10
+#define MAX_NUM_OF_LAYERS 6
#define DPE_PLATFORM_LAYER_IDX 1
#define DPE_SECURE_WORLD_AND_HYPERVISOR_LAYER_IDX 2
/* Below threshold defines the threshold below which a context cannot be destroyed */
@@ -69,10 +68,12 @@
struct layer_context_data_t {
psa_key_id_t cdi_key_id;
uint8_t cdi_seal[DICE_CDI_SIZE];
- uint8_t wrapping_key[DICE_WRAPPING_KEY_SIZE];
+ uint8_t cdi_id[DICE_ID_SIZE];
psa_key_id_t attest_key_id;
+ uint8_t attest_pub_key[DPE_ATTEST_PUB_KEY_SIZE];
+ size_t attest_pub_key_len;
uint8_t cert_buf[DICE_CERT_SIZE];
- size_t cert_buf_size;
+ size_t cert_buf_len;
};
enum layer_state_t {
@@ -150,6 +151,18 @@
*/
void initialise_all_dpe_contexts(void);
+/**
+ * \brief Function to get the pointer to a component context if linked to a layer
+ *
+ * \param[in] layer_idx Index of the linked layer
+ * \param[in] component_idx Index of the component context in the array
+ *
+ * \return Returns pointer to the component context if it is linked to the input
+ * layer else returns NULL
+ */
+struct component_context_t* get_component_if_linked_to_layer(uint16_t layer_idx,
+ uint16_t component_idx);
+
#ifdef __cplusplus
}
#endif
diff --git a/partitions/dice_protection_environment/dpe_crypto_config.h b/partitions/dice_protection_environment/dpe_crypto_config.h
index 8bef476..41bf8c3 100644
--- a/partitions/dice_protection_environment/dpe_crypto_config.h
+++ b/partitions/dice_protection_environment/dpe_crypto_config.h
@@ -9,6 +9,7 @@
#define __DPE_CRYPTO_CONFIG_H__
#include "psa/crypto.h"
+#include "t_cose_common.h"
#ifdef __cplusplus
extern "C" {
@@ -34,6 +35,7 @@
#define DPE_ATTEST_KEY_ALG PSA_ALG_ECDSA(PSA_ALG_SHA_256)
#define DPE_ATTEST_KEY_BITS PSA_BYTES_TO_BITS(PSA_HASH_LENGTH(PSA_ALG_SHA_256))
#define DPE_ATTEST_KEY_USAGE PSA_KEY_USAGE_SIGN_HASH
+#define DPE_ATTEST_PUB_KEY_SIZE PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(DPE_ATTEST_KEY_BITS)
#define DPE_ATTEST_KEY_PAIR_LABEL "Key Pair"
#define DPE_ATTEST_KEY_SALT { \
@@ -43,6 +45,24 @@
0x35, 0xD3, 0x1F, 0x28, 0x28, 0x21, 0xA7, 0x45, 0x0A, 0x02, 0x22, \
0x2A, 0xB1, 0xB3, 0xCF, 0xF1, 0x67, 0x9B, 0x05, 0xAB, 0x1C, 0xA5, \
0xD1, 0xAF, 0xFB, 0x78, 0x9C, 0xCD, 0x2B, 0x0B, 0x3B }
+
+/* DPE Crypto configuration for Certificate creation and signature */
+#define DPE_ID_LABEL "ID"
+#define DPE_ID_SALT { \
+ 0xDB, 0xDB, 0xAE, 0xBC, 0x80, 0x20, 0xDA, 0x9F, 0xF0, 0xDD, 0x5A, \
+ 0x24, 0xC8, 0x3A, 0xA5, 0xA5, 0x42, 0x86, 0xDF, 0xC2, 0x63, 0x03, \
+ 0x1E, 0x32, 0x9B, 0x4D, 0xA1, 0x48, 0x43, 0x06, 0x59, 0xFE, 0x62, \
+ 0xCD, 0xB5, 0xB7, 0xE1, 0xE0, 0x0F, 0xC6, 0x80, 0x30, 0x67, 0x11, \
+ 0xEB, 0x44, 0x4A, 0xF7, 0x72, 0x09, 0x35, 0x94, 0x96, 0xFC, 0xFF, \
+ 0x1D, 0xB9, 0x52, 0x0B, 0xA5, 0x1C, 0x7B, 0x29, 0xEA };
+
+/* As per RFC8152 */
+#define DPE_T_COSE_ALG T_COSE_ALGORITHM_ES256
+#define DPE_T_COSE_KEY_TYPE_VAL 2 /* Elliptic Curve Keys w/ x and y-coordinate */
+#define DPE_T_COSE_KEY_OPS_VAL 2 /* Key used for signature verification */
+#define DPE_T_COSE_KEY_EC2_CURVE_VAL 1 /* NIST P-256 also known as secp256r1 */
+#define DPE_T_COSE_KEY_ALG_VAL -7 /* ECDSA w/ SHA-256 */
+
#ifdef __cplusplus
}
#endif
diff --git a/partitions/dice_protection_environment/dpe_crypto_interface.c b/partitions/dice_protection_environment/dpe_crypto_interface.c
index 8f83666..310adcb 100644
--- a/partitions/dice_protection_environment/dpe_crypto_interface.c
+++ b/partitions/dice_protection_environment/dpe_crypto_interface.c
@@ -6,6 +6,7 @@
*/
#include "dpe_crypto_interface.h"
+#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "dpe_context_mngr.h"
@@ -15,7 +16,9 @@
static const char attest_cdi_label[] = DPE_ATTEST_CDI_LABEL;
static const char attest_key_pair_label[] = DPE_ATTEST_KEY_PAIR_LABEL;
+static const char id_label[] = DPE_ID_LABEL;
static const uint8_t attest_key_salt[] = DPE_ATTEST_KEY_SALT;
+static const uint8_t id_salt[] = DPE_ID_SALT;
static psa_status_t perform_derivation(psa_key_id_t base_key,
const psa_key_attributes_t *key_attr,
@@ -100,6 +103,7 @@
psa_status_t derive_attestation_key(struct layer_context_t *layer_ctx)
{
+ psa_status_t status;
psa_key_attributes_t attest_key_attr = PSA_KEY_ATTRIBUTES_INIT;
/* Set key attributes for Attest key pair derivation */
@@ -109,13 +113,21 @@
psa_set_key_usage_flags(&attest_key_attr, DPE_ATTEST_KEY_USAGE);
/* Perform key pair derivation */
- return perform_derivation(layer_ctx->data.cdi_key_id,
- &attest_key_attr,
- (uint8_t *)&attest_key_pair_label[0],
- sizeof(attest_key_pair_label),
- attest_key_salt,
- sizeof(attest_key_salt),
- &layer_ctx->data.attest_key_id);
+ status = perform_derivation(layer_ctx->data.cdi_key_id,
+ &attest_key_attr,
+ (uint8_t *)&attest_key_pair_label[0],
+ sizeof(attest_key_pair_label),
+ attest_key_salt,
+ sizeof(attest_key_salt),
+ &layer_ctx->data.attest_key_id);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ return psa_export_public_key(layer_ctx->data.attest_key_id,
+ &layer_ctx->data.attest_pub_key[0],
+ sizeof(layer_ctx->data.attest_pub_key),
+ &layer_ctx->data.attest_pub_key_len);
}
psa_status_t create_layer_cdi_key(struct layer_context_t *layer_ctx,
@@ -150,16 +162,56 @@
return PSA_SUCCESS;
}
-psa_status_t create_layer_certificate(struct layer_context_t *layer_ctx)
+psa_status_t derive_id_from_public_key(struct layer_context_t *layer_ctx)
{
- //TODO:
- (void)layer_ctx;
- return PSA_SUCCESS;
-}
+ psa_status_t status;
+ psa_key_attributes_t derive_key_attr = PSA_KEY_ATTRIBUTES_INIT;
+ psa_key_attributes_t base_attr = PSA_KEY_ATTRIBUTES_INIT;
+ size_t output_id_len;
-psa_status_t store_layer_certificate(struct layer_context_t *layer_ctx)
-{
- //TODO:
- (void)layer_ctx;
- return PSA_SUCCESS;
+ psa_key_id_t base_key = PSA_KEY_ID_NULL;
+ psa_key_id_t derived_key_id = PSA_KEY_ID_NULL;
+
+ psa_set_key_type(&base_attr, PSA_KEY_TYPE_DERIVE);
+ psa_set_key_algorithm(&base_attr, PSA_ALG_HKDF(PSA_ALG_SHA_256));
+ psa_set_key_bits(&base_attr, PSA_BYTES_TO_BITS(layer_ctx->data.attest_pub_key_len));
+ psa_set_key_usage_flags(&base_attr, PSA_KEY_USAGE_DERIVE);
+
+ status = psa_import_key(&base_attr,
+ &layer_ctx->data.attest_pub_key[0],
+ layer_ctx->data.attest_pub_key_len,
+ &base_key);
+ if (status != PSA_SUCCESS) {
+ return status;
+ }
+
+ /* Derive Key attributes same as CDI attributes except the label */
+ psa_set_key_type(&derive_key_attr, PSA_KEY_TYPE_RAW_DATA);
+ psa_set_key_algorithm(&derive_key_attr, PSA_ALG_HKDF(PSA_ALG_SHA_256));
+ psa_set_key_bits(&derive_key_attr, PSA_BYTES_TO_BITS(DICE_ID_SIZE));
+ psa_set_key_usage_flags(&derive_key_attr, PSA_KEY_USAGE_EXPORT);
+
+ /* Perform ID derivation */
+ /* Supply the ID label as an input to the key derivation */
+ status = perform_derivation(base_key,
+ &derive_key_attr,
+ (uint8_t *) &id_label[0],
+ sizeof(id_label),
+ id_salt,
+ sizeof(id_salt),
+ &derived_key_id);
+ if (status != PSA_SUCCESS) {
+ goto err_destroy_base_key;
+ }
+ status = psa_export_key(derived_key_id,
+ &layer_ctx->data.cdi_id[0],
+ sizeof(layer_ctx->data.cdi_id),
+ &output_id_len);
+
+ (void)psa_destroy_key(derived_key_id);
+
+err_destroy_base_key:
+ (void)psa_destroy_key(base_key);
+
+ return status;
}
diff --git a/partitions/dice_protection_environment/dpe_crypto_interface.h b/partitions/dice_protection_environment/dpe_crypto_interface.h
index 02ab5b1..43b4728 100644
--- a/partitions/dice_protection_environment/dpe_crypto_interface.h
+++ b/partitions/dice_protection_environment/dpe_crypto_interface.h
@@ -59,6 +59,15 @@
psa_status_t derive_sealing_cdi(struct layer_context_t *layer_ctx);
/**
+ * \brief Derives certificate id from the layer's attestation public key
+ *
+ * \param[in] layer_ctx Pointer to current layer context.
+ *
+ * \return Returns error code as specified in \ref psa_status_t
+ */
+psa_status_t derive_id_from_public_key(struct layer_context_t *layer_ctx);
+
+/**
* \brief Derives wrapping key pair for a layer
*
* \param[in] layer_ctx Pointer to current layer context.
@@ -67,24 +76,6 @@
*/
psa_status_t derive_wrapping_key(struct layer_context_t *layer_ctx);
-/**
- * \brief Create and sign the certificate for a layer
- *
- * \param[in] layer_ctx Pointer to current layer context.
- *
- * \return Returns error code as specified in \ref psa_status_t
- */
-psa_status_t create_layer_certificate(struct layer_context_t *layer_ctx);
-
-/**
- * \brief Stores signed certificate for a layer
- *
- * \param[in] layer_ctx Pointer to current layer context.
- *
- * \return Returns error code as specified in \ref psa_status_t
- */
-psa_status_t store_layer_certificate(struct layer_context_t *layer_ctx);
-
#ifdef __cplusplus
}
#endif
diff --git a/partitions/dice_protection_environment/dpe_log.c b/partitions/dice_protection_environment/dpe_log.c
index 5e4da40..05ee08c 100644
--- a/partitions/dice_protection_environment/dpe_log.c
+++ b/partitions/dice_protection_environment/dpe_log.c
@@ -99,4 +99,14 @@
print_byte_array(label, label_size);
}
+void log_intermediate_certificate(uint16_t layer_idx,
+ const uint8_t *cert_buf,
+ size_t cert_buf_size)
+{
+ LOG_DBGFMT("DPE Intermediate Certificate:\r\n");
+ LOG_DBGFMT(" - layer index = %d\r\n", layer_idx);
+ LOG_DBGFMT(" - certificate =");
+ print_byte_array(cert_buf, cert_buf_size);
+}
+
#endif /* TFM_PARTITION_LOG_LEVEL */
diff --git a/partitions/dice_protection_environment/dpe_log.h b/partitions/dice_protection_environment/dpe_log.h
index 8f2f5b8..e3c7428 100644
--- a/partitions/dice_protection_environment/dpe_log.h
+++ b/partitions/dice_protection_environment/dpe_log.h
@@ -48,12 +48,20 @@
const uint8_t *label,
size_t label_size);
+/**
+ * \brief Log intermediate layer certificate contents.
+ */
+void log_intermediate_certificate(uint16_t layer_idx,
+ const uint8_t *cert_buf,
+ size_t cert_buf_size);
+
#else /* TFM_PARTITION_LOG_LEVEL */
#define log_derive_rot_context(...)
#define log_derive_child(...)
#define log_destroy_context(...)
#define log_certify_key(...)
+#define log_intermediate_certificate(...)
#endif /* TFM_PARTITION_LOG_LEVEL */
diff --git a/partitions/dice_protection_environment/interface/include/dice_protection_environment.h b/partitions/dice_protection_environment/interface/include/dice_protection_environment.h
index 12082ad..f1e0ef0 100644
--- a/partitions/dice_protection_environment/interface/include/dice_protection_environment.h
+++ b/partitions/dice_protection_environment/interface/include/dice_protection_environment.h
@@ -33,6 +33,7 @@
#define DPE_ARGUMENT_NOT_SUPPORTED ((dpe_error_t)4)
#define DPE_SESSION_EXHAUSTED ((dpe_error_t)5)
#define DPE_INSUFFICIENT_MEMORY ((dpe_error_t)128)
+#define DPE_ERR_CBOR_FORMATTING ((dpe_error_t)129)
/**
* \brief Performs the DICE computation to derive a child context and optionally