DPE: Add Destroy Context command
Signed-off-by: Maulik Patel <maulik.patel@arm.com>
Change-Id: Ibd70e6d7c61672c86a39f3d026d8e083f0b96bc8
diff --git a/partitions/dice_protection_environment/dpe_cmd_decode.c b/partitions/dice_protection_environment/dpe_cmd_decode.c
index 0c4215f..ff2595e 100644
--- a/partitions/dice_protection_environment/dpe_cmd_decode.c
+++ b/partitions/dice_protection_environment/dpe_cmd_decode.c
@@ -181,6 +181,52 @@
return DPE_NO_ERROR;
}
+static dpe_error_t decode_destroy_context(QCBORDecodeContext *decode_ctx,
+ QCBOREncodeContext *encode_ctx)
+{
+ dpe_error_t dpe_err;
+ QCBORError qcbor_err;
+ UsefulBufC out;
+ int context_handle;
+ bool destroy_recursively;
+
+ /* Decode Destroy context command */
+ QCBORDecode_EnterMap(decode_ctx, NULL);
+
+ QCBORDecode_GetByteStringInMapN(decode_ctx, DPE_DESTROY_CONTEXT_HANDLE,
+ &out);
+ if (out.len != sizeof(context_handle)) {
+ return DPE_INVALID_COMMAND;
+ }
+ memcpy(&context_handle, out.ptr, out.len);
+
+ QCBORDecode_GetBoolInMapN(decode_ctx, DPE_DESTROY_CONTEXT_RECURSIVELY,
+ &destroy_recursively);
+
+ QCBORDecode_ExitMap(decode_ctx);
+
+ /* Exit top level array */
+ QCBORDecode_ExitArray(decode_ctx);
+
+ /* Finish and check for errors before using decoded values */
+ qcbor_err = QCBORDecode_Finish(decode_ctx);
+ if (qcbor_err != QCBOR_SUCCESS) {
+ return DPE_INVALID_COMMAND;
+ }
+
+ dpe_err = destroy_context_request(context_handle, destroy_recursively);
+ if (dpe_err != DPE_NO_ERROR) {
+ return dpe_err;
+ }
+
+ /* Encode response */
+ QCBOREncode_OpenArray(encode_ctx);
+ QCBOREncode_AddInt64(encode_ctx, DPE_NO_ERROR);
+ QCBOREncode_CloseArray(encode_ctx);
+
+ return DPE_NO_ERROR;
+}
+
static dpe_error_t decode_certify_key(QCBORDecodeContext *decode_ctx,
QCBOREncodeContext *encode_ctx)
{
@@ -313,6 +359,9 @@
case DPE_CERTIFY_KEY:
dpe_err = decode_certify_key(&decode_ctx, &encode_ctx);
break;
+ case DPE_DESTROY_CONTEXT:
+ dpe_err = decode_destroy_context(&decode_ctx, &encode_ctx);
+ break;
default:
dpe_err = DPE_INVALID_COMMAND;
break;
diff --git a/partitions/dice_protection_environment/dpe_context_mngr.c b/partitions/dice_protection_environment/dpe_context_mngr.c
index d2bc2ab..8750922 100644
--- a/partitions/dice_protection_environment/dpe_context_mngr.c
+++ b/partitions/dice_protection_environment/dpe_context_mngr.c
@@ -410,3 +410,62 @@
return DPE_NO_ERROR;
}
+
+dpe_error_t destroy_context_request(int input_ctx_handle,
+ bool destroy_recursively)
+{
+ uint16_t input_ctx_idx, linked_layer_idx;
+ int i;
+ bool is_layer_empty;
+
+ log_destroy_context(input_ctx_handle, destroy_recursively);
+
+ /* Get child component index and linked layer from the input handle */
+ input_ctx_idx = GET_IDX(input_ctx_handle);
+
+#ifdef TFM_S_REG_TEST
+ if (input_ctx_idx == 0) {
+ invalidate_layer(DPE_ROT_LAYER_IDX);
+ set_context_to_default(0);
+ return DPE_NO_ERROR;
+ }
+#endif /* TFM_S_REG_TEST */
+
+ /* Validate input handle */
+ if (!is_input_handle_valid(input_ctx_handle)) {
+ return DPE_INVALID_ARGUMENT;
+ }
+ linked_layer_idx = component_ctx_array[input_ctx_idx].linked_layer_idx;
+
+#ifndef TFM_S_REG_TEST
+ if (linked_layer_idx <= DPE_DESTROY_CONTEXT_THRESHOLD_LAYER_IDX) {
+ /* All layers till hypervisor cannot be destroyed dynamically */
+ return DPE_INVALID_ARGUMENT;
+ }
+#endif /* !TFM_S_REG_TEST */
+
+
+ if (!destroy_recursively) {
+ set_context_to_default(input_ctx_idx);
+ } else {
+ //TODO: To be implemented
+ }
+
+ assert(linked_layer_idx < MAX_NUM_OF_LAYERS);
+
+ /* Close the layer if all of its contexts are destroyed */
+ is_layer_empty = true;
+ for (i = 0; i < MAX_NUM_OF_COMPONENTS; i++) {
+ if (component_ctx_array[i].linked_layer_idx == linked_layer_idx) {
+ /* There are active component context in the layer */
+ is_layer_empty = false;
+ break;
+ }
+ }
+
+ if (is_layer_empty) {
+ invalidate_layer(linked_layer_idx);
+ }
+
+ return DPE_NO_ERROR;
+}
diff --git a/partitions/dice_protection_environment/dpe_context_mngr.h b/partitions/dice_protection_environment/dpe_context_mngr.h
index 8335263..8e679f6 100644
--- a/partitions/dice_protection_environment/dpe_context_mngr.h
+++ b/partitions/dice_protection_environment/dpe_context_mngr.h
@@ -23,10 +23,16 @@
#define INVALID_HANDLE 0xFFFFFFFF
#define INVALID_COMPONENT_IDX 0xFFFF
#define INVALID_NONCE_VALUE 0xFFFF
-#define MAX_NUM_OF_COMPONENTS 30
-#define DPE_ROT_LAYER_IDX 0
-#define MAX_NUM_OF_LAYERS 10
#define INVALID_LAYER_IDX 65535
+#define DPE_ROT_LAYER_IDX 0
+
+/* Below configuration defines are platform dependant */
+#define MAX_NUM_OF_COMPONENTS 30
+#define MAX_NUM_OF_LAYERS 10
+#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 */
+#define DPE_DESTROY_CONTEXT_THRESHOLD_LAYER_IDX DPE_SECURE_WORLD_AND_HYPERVISOR_LAYER_IDX
/* Most significant 16 bits represent nonce & remaining 16 bits represent component index */
#define GET_IDX(handle) ((handle) & 0xffff)
@@ -123,6 +129,19 @@
int *new_parent_context_handle);
/**
+ * \brief Destroys a component context and optionally depending on argument
+ * destroy_recursively, destroys all its child context too.
+ *
+ * \param[in] input_context_handle Input handle to child component context
+ * \param[in] destroy_recursively Flag to indicate if all derived contexts
+ * should also be destroyed recursively.
+ *
+ * \return Returns error code of type dpe_error_t
+ */
+dpe_error_t destroy_context_request(int input_ctx_handle,
+ bool destroy_recursively);
+
+/**
* \brief Initialise all DPE Layer and component contexts
*
*/
diff --git a/partitions/dice_protection_environment/dpe_log.c b/partitions/dice_protection_environment/dpe_log.c
index 5a37706..5e4da40 100644
--- a/partitions/dice_protection_environment/dpe_log.c
+++ b/partitions/dice_protection_environment/dpe_log.c
@@ -74,6 +74,14 @@
LOG_DBGFMT(" - client_id = %d\r\n", client_id);
}
+void log_destroy_context(int context_handle, bool destroy_recursively)
+{
+ LOG_DBGFMT("DPE DestroyContext:\r\n");
+ LOG_DBGFMT(" - context_handle index = %d\r\n", GET_IDX(context_handle));
+ LOG_DBGFMT(" - context_handle nonce = %d\r\n", GET_NONCE(context_handle));
+ LOG_DBGFMT(" - destroy_recursively = %d\r\n", destroy_recursively);
+}
+
void log_certify_key(int context_handle,
bool retain_context,
const uint8_t *public_key,
diff --git a/partitions/dice_protection_environment/dpe_log.h b/partitions/dice_protection_environment/dpe_log.h
index 97eb752..8f2f5b8 100644
--- a/partitions/dice_protection_environment/dpe_log.h
+++ b/partitions/dice_protection_environment/dpe_log.h
@@ -33,6 +33,12 @@
int32_t client_id);
/**
+ * \brief Log the destroy context command parameters.
+ */
+void log_destroy_context(int context_handle,
+ bool destroy_recursively);
+
+/**
* \brief Log the certify key command parameters.
*/
void log_certify_key(int context_handle,
@@ -46,6 +52,7 @@
#define log_derive_rot_context(...)
#define log_derive_child(...)
+#define log_destroy_context(...)
#define log_certify_key(...)
#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 8aefec2..12082ad 100644
--- a/partitions/dice_protection_environment/interface/include/dice_protection_environment.h
+++ b/partitions/dice_protection_environment/interface/include/dice_protection_environment.h
@@ -67,6 +67,20 @@
int *new_parent_context_handle);
/**
+ * \brief Destroys a DPE context.
+ *
+ * \param[in] context_handle Input context handle for the DPE context to
+ * be destroyed.
+ * \param[in] destroy_recursively Flag to indicate whether all derived contexts
+ * should also be destroyed recursively.
+ *
+ * \return Returns error code of type dpe_error_t
+ */
+dpe_error_t
+dpe_destroy_context(int context_handle,
+ bool destroy_recursively);
+
+/**
* \brief Certifies an attestation key with a new leaf certificate and returns
* the certificate chain containing all certificates up to and including
* the new leaf certificate.
diff --git a/partitions/dice_protection_environment/interface/include/dpe_client.h b/partitions/dice_protection_environment/interface/include/dpe_client.h
index 8a21d26..ef4e376 100644
--- a/partitions/dice_protection_environment/interface/include/dpe_client.h
+++ b/partitions/dice_protection_environment/interface/include/dpe_client.h
@@ -59,6 +59,11 @@
DPE_DERIVE_CHILD_INTERNAL_INPUTS = 8,
};
+enum dpe_destroy_context_input_labels_t {
+ DPE_DESTROY_CONTEXT_HANDLE = 1,
+ DPE_DESTROY_CONTEXT_RECURSIVELY = 2,
+};
+
enum dpe_derive_child_output_labels_t {
DPE_DERIVE_CHILD_NEW_CONTEXT_HANDLE = 1,
DPE_DERIVE_CHILD_NEW_SESSION_RESPONDER_HANDSHAKE = 2,
diff --git a/partitions/dice_protection_environment/interface/src/dpe_cmd_encode.c b/partitions/dice_protection_environment/interface/src/dpe_cmd_encode.c
index 35c7631..1112560 100644
--- a/partitions/dice_protection_environment/interface/src/dpe_cmd_encode.c
+++ b/partitions/dice_protection_environment/interface/src/dpe_cmd_encode.c
@@ -25,6 +25,11 @@
int new_parent_context_handle;
};
+struct destroy_context_input_t {
+ int context_handle;
+ bool destroy_recursively;
+};
+
struct certify_key_input_t {
int context_handle;
bool retain_context;
@@ -120,6 +125,31 @@
return QCBOREncode_Finish(&encode_ctx, encoded_buf);
}
+static QCBORError encode_destroy_context(const struct destroy_context_input_t *args,
+ UsefulBuf buf,
+ UsefulBufC *encoded_buf)
+{
+ QCBOREncodeContext encode_ctx;
+
+ QCBOREncode_Init(&encode_ctx, buf);
+
+ QCBOREncode_OpenArray(&encode_ctx);
+ QCBOREncode_AddUInt64(&encode_ctx, DPE_DESTROY_CONTEXT);
+
+ /* Encode DestroyContext command */
+ QCBOREncode_OpenMap(&encode_ctx);
+ QCBOREncode_AddBytesToMapN(&encode_ctx, DPE_DESTROY_CONTEXT_HANDLE,
+ (UsefulBufC){ &args->context_handle,
+ sizeof(args->context_handle) });
+ QCBOREncode_AddBoolToMapN(&encode_ctx, DPE_DESTROY_CONTEXT_RECURSIVELY,
+ args->destroy_recursively);
+ QCBOREncode_CloseMap(&encode_ctx);
+
+ QCBOREncode_CloseArray(&encode_ctx);
+
+ return QCBOREncode_Finish(&encode_ctx, encoded_buf);
+}
+
static QCBORError decode_derive_child_response(UsefulBufC encoded_buf,
struct derive_child_output_t *args,
dpe_error_t *dpe_err)
@@ -164,6 +194,25 @@
return QCBORDecode_Finish(&decode_ctx);
}
+static QCBORError decode_destroy_context_response(UsefulBufC encoded_buf,
+ dpe_error_t *dpe_err)
+{
+ QCBORDecodeContext decode_ctx;
+ int64_t response_dpe_err;
+
+ QCBORDecode_Init(&decode_ctx, encoded_buf, QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORDecode_EnterArray(&decode_ctx, NULL);
+
+ /* Get the error code from the response */
+ QCBORDecode_GetInt64(&decode_ctx, &response_dpe_err);
+ *dpe_err = (dpe_error_t)response_dpe_err;
+
+ QCBORDecode_ExitArray(&decode_ctx);
+
+ return QCBORDecode_Finish(&decode_ctx);
+}
+
static QCBORError encode_certify_key(const struct certify_key_input_t *args,
UsefulBuf buf,
UsefulBufC *encoded_buf)
@@ -291,6 +340,41 @@
return DPE_NO_ERROR;
}
+dpe_error_t dpe_destroy_context(int context_handle, bool destroy_recursively)
+{
+ int32_t service_err;
+ dpe_error_t dpe_err;
+ QCBORError qcbor_err;
+ UsefulBufC encoded_buf;
+ UsefulBuf_MAKE_STACK_UB(cmd_buf, 12);
+
+ const struct destroy_context_input_t in_args = {
+ context_handle,
+ destroy_recursively
+ };
+
+ qcbor_err = encode_destroy_context(&in_args, cmd_buf, &encoded_buf);
+ if (qcbor_err != QCBOR_SUCCESS) {
+ return DPE_INTERNAL_ERROR;
+ }
+
+ service_err = dpe_client_call(encoded_buf.ptr, encoded_buf.len,
+ cmd_buf.ptr, &cmd_buf.len);
+ if (service_err != 0) {
+ return DPE_INTERNAL_ERROR;
+ }
+
+ qcbor_err = decode_destroy_context_response(UsefulBuf_Const(cmd_buf),
+ &dpe_err);
+ if (qcbor_err != QCBOR_SUCCESS) {
+ return DPE_INTERNAL_ERROR;
+ } else if (dpe_err != DPE_NO_ERROR) {
+ return dpe_err;
+ }
+
+ return DPE_NO_ERROR;
+}
+
dpe_error_t dpe_certify_key(int context_handle,
bool retain_context,
const uint8_t *public_key,