DPE: Add context manager code

It manages handles, component contexts and layer contexts.

Signed-off-by: Maulik Patel <maulik.patel@arm.com>
Change-Id: I280a5096792f7c286695e9d567e09e00850ac101
diff --git a/partitions/dice_protection_environment/dpe_context_mngr.c b/partitions/dice_protection_environment/dpe_context_mngr.c
new file mode 100644
index 0000000..d2bc2ab
--- /dev/null
+++ b/partitions/dice_protection_environment/dpe_context_mngr.c
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include "dpe_context_mngr.h"
+#include <assert.h>
+#include <string.h>
+#include "dice_protection_environment.h"
+#include "dpe_log.h"
+#include "psa/crypto.h"
+
+static struct component_context_t component_ctx_array[MAX_NUM_OF_COMPONENTS];
+static struct layer_context_t layer_ctx_array[MAX_NUM_OF_LAYERS];
+
+static int get_free_component_context_index(void)
+{
+    int i;
+
+    for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
+        if (!component_ctx_array[i].in_use) {
+            break;
+        }
+    }
+
+    if (i >= MAX_NUM_OF_COMPONENTS) {
+        /* No free index left in the array -- all used up! */
+        return -1;
+    }
+
+    return i;
+}
+
+static inline void invalidate_handle(int *handle)
+{
+    *handle = INVALID_HANDLE;
+}
+
+static dpe_error_t renew_nonce(int *handle)
+{
+    uint16_t nonce;
+
+    psa_status_t status = psa_generate_random((uint8_t *)&nonce, sizeof(nonce));
+    if (status != PSA_SUCCESS) {
+        return DPE_INTERNAL_ERROR;
+    }
+    *handle = SET_NONCE(*handle, nonce);
+
+    return DPE_NO_ERROR;
+}
+
+static dpe_error_t generate_new_handle(int *out_handle)
+{
+    /* Find the free component array element */
+    int free_component_idx = get_free_component_context_index();
+    if (free_component_idx < 0) {
+        return DPE_INSUFFICIENT_MEMORY;
+    }
+
+    *out_handle = SET_IDX(*out_handle, free_component_idx);
+
+    return renew_nonce(out_handle);
+}
+
+static void set_context_to_default(int i)
+{
+    component_ctx_array[i].in_use = false;
+    component_ctx_array[i].is_leaf = false;
+    component_ctx_array[i].nonce = INVALID_NONCE_VALUE;
+    component_ctx_array[i].parent_idx = INVALID_COMPONENT_IDX;
+    component_ctx_array[i].linked_layer_idx = INVALID_LAYER_IDX;
+    (void)memset(&component_ctx_array[i].data, 0, sizeof(struct component_context_data_t));
+    //TODO: Question: how to initialise MHU Id mapping?
+    /* Allow component to be derived by default */
+}
+
+static void invalidate_layer(int i)
+{
+    layer_ctx_array[i].state = LAYER_STATE_CLOSED;
+    layer_ctx_array[i].parent_layer_idx = INVALID_LAYER_IDX;
+    (void)memset(&layer_ctx_array[i].data, 0, sizeof(struct layer_context_data_t));
+}
+
+void initialise_all_dpe_contexts(void)
+{
+    int i;
+
+    for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
+        set_context_to_default(i);
+    }
+
+    for (i = 0; i < MAX_NUM_OF_LAYERS; i++) {
+        invalidate_layer(i);
+    }
+}
+
+static dpe_error_t copy_dice_input(struct component_context_t *dest_ctx,
+                                   const DiceInputValues *dice_inputs)
+{
+    size_t hash_len;
+    psa_status_t status;
+
+    memcpy(&dest_ctx->data.measurement_value, dice_inputs->code_hash,
+           DICE_HASH_SIZE);
+    memcpy(&dest_ctx->data.measurement_descriptor,
+           dice_inputs->code_descriptor,
+           dice_inputs->code_descriptor_size);
+
+    dest_ctx->data.measurement_descriptor_size =
+                                      dice_inputs->code_descriptor_size;
+
+    memcpy(&dest_ctx->data.signer_id, dice_inputs->authority_hash, DICE_HASH_SIZE);
+    memcpy(&dest_ctx->data.signer_id_descriptor,
+           dice_inputs->authority_descriptor,
+           dice_inputs->authority_descriptor_size);
+
+    dest_ctx->data.signer_id_descriptor_size =
+                                         dice_inputs->authority_descriptor_size;
+
+    if (dice_inputs->config_type == kDiceConfigTypeInline) {
+        /* Copy config_value */
+        memcpy(&dest_ctx->data.config_value, dice_inputs->config_value,
+               DICE_INLINE_CONFIG_SIZE);
+
+    } else {
+        /* Copy config descriptor */
+        memcpy(&dest_ctx->data.config_descriptor, dice_inputs->config_descriptor,
+                dice_inputs->config_descriptor_size);
+        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,
+                                  dice_inputs->config_descriptor,
+                                  dice_inputs->config_descriptor_size,
+                                  dest_ctx->data.config_value,
+                                  sizeof(dest_ctx->data.config_value),
+                                  &hash_len);
+
+        if (status != PSA_SUCCESS) {
+            return DPE_INTERNAL_ERROR;
+        }
+    }
+
+    dest_ctx->data.mode = dice_inputs->mode;
+    memcpy(&dest_ctx->data.hidden, dice_inputs->hidden, DICE_HIDDEN_SIZE);
+
+    return DPE_NO_ERROR;
+}
+
+static bool is_dice_input_valid(const DiceInputValues *dice_inputs)
+{
+    if ((dice_inputs->code_descriptor_size > DICE_CODE_DESCRIPTOR_MAX_SIZE) ||
+        (dice_inputs->authority_descriptor_size > DICE_AUTHORITY_DESCRIPTOR_MAX_SIZE) ||
+        (dice_inputs->config_descriptor_size > DICE_CONFIG_DESCRIPTOR_MAX_SIZE)) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool is_input_handle_valid(int input_context_handle)
+{
+    uint16_t idx = GET_IDX(input_context_handle);
+    uint16_t nonce = GET_NONCE(input_context_handle);
+
+    /* Validate input handle id and nonce */
+    if ((idx >= MAX_NUM_OF_COMPONENTS) || (nonce == INVALID_NONCE_VALUE)) {
+        return false;
+    }
+
+    if (nonce == component_ctx_array[idx].nonce) {
+        return true;
+    }
+
+    return false;
+}
+
+static dpe_error_t derive_child_create_certificate(uint16_t curr_idx)
+{
+    //TODO: Implementation pending
+    /* Finalise the layer */
+    layer_ctx_array[curr_idx].state = LAYER_STATE_FINALISED;
+    return DPE_NO_ERROR;
+}
+
+static uint16_t open_new_layer(void)
+{
+    int i;
+
+    for (i = 0; i < MAX_NUM_OF_LAYERS; i++) {
+        if (layer_ctx_array[i].state == LAYER_STATE_CLOSED) {
+            layer_ctx_array[i].state = LAYER_STATE_OPEN;
+            return i;
+        }
+    }
+
+    return INVALID_LAYER_IDX;
+}
+
+static inline void link_layer(uint16_t child_layer, uint16_t parent_layer)
+{
+    layer_ctx_array[child_layer].parent_layer_idx = parent_layer;
+}
+
+dpe_error_t derive_rot_context(const DiceInputValues *dice_inputs,
+                               int *new_child_ctx_handle,
+                               int *new_parent_ctx_handle)
+{
+    int status;
+    struct component_context_t *child_comp_ctx, *new_child_ctx;
+    uint16_t new_layer_idx;
+
+    log_derive_rot_context(dice_inputs);
+
+    /* Validate dice inputs */
+    if (!is_dice_input_valid(dice_inputs)) {
+        return DPE_INVALID_ARGUMENT;
+    }
+
+    child_comp_ctx = &component_ctx_array[0];
+    status = copy_dice_input(child_comp_ctx, dice_inputs);
+    if (status != DPE_NO_ERROR) {
+        return status;
+    }
+
+    child_comp_ctx->in_use = true;
+    /* Link context to RoT Layer */
+    child_comp_ctx->linked_layer_idx = DPE_ROT_LAYER_IDX;
+    /* Parent is same as child for RoT context */
+    child_comp_ctx->parent_idx = 0;
+    /* Parent not deriving any more children */
+    invalidate_handle(new_parent_ctx_handle);
+
+    //TODO: Update expected_mhu_id of derived child
+    /* Create certificate for RoT layer */
+    status = derive_child_create_certificate(DPE_ROT_LAYER_IDX);
+    if (status != DPE_NO_ERROR) {
+        return status;
+    }
+
+    /* Generate new handle for child for subsequent requests */
+    if (generate_new_handle(new_child_ctx_handle) != DPE_NO_ERROR) {
+        return DPE_INTERNAL_ERROR;
+    }
+
+    /* Update the component context array element as pointed by newly generated handle */
+    new_child_ctx = &component_ctx_array[GET_IDX(*new_child_ctx_handle)];
+    new_child_ctx->nonce = GET_NONCE(*new_child_ctx_handle);
+    new_child_ctx->in_use = true;
+    /* New child's parent is current RoT component which is evaluated as 0 */
+    new_child_ctx->parent_idx = 0;
+
+    /* Open new layer since RoT layer is finalised and
+     * link the new child to this new layer
+     */
+    new_layer_idx = open_new_layer();
+    new_child_ctx->linked_layer_idx = new_layer_idx;
+
+    /* Link this new layer to the RoT Layer */
+    link_layer(new_layer_idx, DPE_ROT_LAYER_IDX);
+
+    return DPE_NO_ERROR;
+}
+
+static inline bool is_input_client_id_valid(int32_t client_id)
+{
+    //TODO: Waiting for implementation
+    return true;
+}
+
+static void assign_layer_to_context(struct component_context_t *new_ctx)
+{
+    uint16_t new_layer_idx, parent_layer_idx;
+
+    assert(new_ctx->parent_idx < MAX_NUM_OF_COMPONENTS);
+
+    parent_layer_idx = component_ctx_array[new_ctx->parent_idx].linked_layer_idx;
+    assert(parent_layer_idx < MAX_NUM_OF_LAYERS);
+
+    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();
+        /* Link this context to the new layer */
+        new_ctx->linked_layer_idx = new_layer_idx;
+        /* New layer's parent is current layer */
+        link_layer(new_layer_idx, parent_layer_idx);
+
+    } else {
+        /* Parent comp's layer is not yet finalised, link
+         * new component to the same layer as parent
+         */
+        new_ctx->linked_layer_idx = parent_layer_idx;
+    }
+}
+
+dpe_error_t derive_child_request(int input_ctx_handle,
+                                 bool retain_parent_context,
+                                 bool allow_child_to_derive,
+                                 bool create_certificate,
+                                 const DiceInputValues *dice_inputs,
+                                 int32_t client_id,
+                                 int *new_child_ctx_handle,
+                                 int *new_parent_ctx_handle)
+{
+    dpe_error_t status;
+    struct component_context_t *child_ctx, *parent_ctx, *new_ctx;
+    uint16_t input_child_idx, input_parent_idx;
+
+#ifdef TFM_S_REG_TEST
+    if (layer_ctx_array[DPE_ROT_LAYER_IDX].state != LAYER_STATE_FINALISED) {
+        return derive_rot_context(dice_inputs,
+                                  new_child_ctx_handle,
+                                  new_parent_ctx_handle);
+    }
+#endif /* TFM_S_REG_TEST */
+
+    log_derive_child(input_ctx_handle, retain_parent_context,
+                     allow_child_to_derive, create_certificate, dice_inputs,
+                     client_id);
+
+    /* Validate dice inputs */
+    if (!is_dice_input_valid(dice_inputs)) {
+        return DPE_INVALID_ARGUMENT;
+    }
+
+    /* Validate input handle */
+    if (!is_input_handle_valid(input_ctx_handle)) {
+        return DPE_INVALID_ARGUMENT;
+    }
+    /* Get child component index from the input handle */
+    input_child_idx = GET_IDX(input_ctx_handle);
+    /* Get parent index of input referenced child component */
+    input_parent_idx = component_ctx_array[input_child_idx].parent_idx;
+
+    /* Below check is for safety only; It should not happen
+     * input_child_idx is already checked above in is_input_handle_valid()
+     */
+    assert(input_parent_idx < MAX_NUM_OF_COMPONENTS);
+
+    child_ctx = &component_ctx_array[input_child_idx];
+    parent_ctx = &component_ctx_array[input_parent_idx];
+
+    //TODO:  Question: how to get mhu id of incoming request?
+    if (!is_input_client_id_valid(client_id)) {
+        return DPE_INVALID_ARGUMENT;
+    }
+
+    /* Copy dice input to the child component context */
+    status = copy_dice_input(child_ctx, dice_inputs);
+    if (status != DPE_NO_ERROR) {
+        return status;
+    }
+
+    if (create_certificate) {
+        status = derive_child_create_certificate(child_ctx->linked_layer_idx);
+        if (status != DPE_NO_ERROR) {
+            return status;
+        }
+    }
+
+    if (allow_child_to_derive) {
+        /* Generate new handle for child for subsequent requests */
+        if (generate_new_handle(new_child_ctx_handle) != DPE_NO_ERROR) {
+            return DPE_INTERNAL_ERROR;
+        }
+        /* Update the component context array element as pointed by newly generated handle */
+        new_ctx = &component_ctx_array[GET_IDX(*new_child_ctx_handle)];
+        /* Update nonce in new child component context */
+        new_ctx->nonce = GET_NONCE(*new_child_ctx_handle);
+        /* Update parent idx in new child component context */
+        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);
+
+    } else {
+        /* Child not deriving any children */
+        /* Tag this component as a leaf */
+        child_ctx->is_leaf = true;
+        invalidate_handle(new_child_ctx_handle);
+        /* Renew nonce of child context so it cannot be used again */
+        child_ctx->nonce = INVALID_NONCE_VALUE;
+    }
+
+    if (retain_parent_context) {
+        /* Parent deriving multiple children */
+        /* Generate new handle for child for the same parent for subsequent requests */
+        if (generate_new_handle(new_parent_ctx_handle) != DPE_NO_ERROR) {
+            return DPE_INTERNAL_ERROR;
+        }
+        /* Update the component context array element as pointed by newly generated handle */
+        new_ctx = &component_ctx_array[GET_IDX(*new_parent_ctx_handle)];
+        /* Update nonce in new child component context */
+        new_ctx->nonce = GET_NONCE(*new_parent_ctx_handle);
+        /* Update parent idx in new child component context */
+        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);
+
+    } else {
+        /* Parent not deriving any more children */
+        /* No need to return parent handle */
+        invalidate_handle(new_parent_ctx_handle);
+        /* Renew nonce of parent context so it cannot be used again */
+        parent_ctx->nonce = INVALID_NONCE_VALUE;
+    }
+
+    return DPE_NO_ERROR;
+}