Test Persistent Object with keys

xtest 1014 is introduced to test TEE_CreatePersistentObject() associated
with a key.

Suggested-by: Miraje Gentilal <miraje.gentilal@hotmail.com>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Signed-off-by: Pascal Brand <pascal.brand@st.com>
diff --git a/host/xtest/xtest_6000.c b/host/xtest/xtest_6000.c
index f95155b..dacadff 100644
--- a/host/xtest/xtest_6000.c
+++ b/host/xtest/xtest_6000.c
@@ -1255,6 +1255,26 @@
 	TEEC_CloseSession(&sess);
 }
 
+static void xtest_tee_test_6013(ADBG_Case_t *c)
+{
+	TEEC_Session sess;
+	uint32_t orig;
+	TEEC_Operation op = TEEC_OPERATION_INITIALIZER;
+
+	if (!ADBG_EXPECT_TEEC_SUCCESS(c,
+		xtest_teec_open_session(&sess, &storage_ta_uuid, NULL, &orig)))
+		return;
+
+	op.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE,
+					 TEEC_NONE, TEEC_NONE);
+
+	ADBG_EXPECT_TEEC_SUCCESS(c,
+		TEEC_InvokeCommand(&sess, TA_STORAGE_CMD_KEY_IN_PERSISTENT,
+				   &op, &orig));
+
+	TEEC_CloseSession(&sess);
+}
+
 ADBG_CASE_DEFINE(
 	XTEST_TEE_6001, xtest_tee_test_6001,
 	/* Title */
@@ -1400,3 +1420,15 @@
     /* How to implement */
     "Description of how to implement ..."
 );
+
+ADBG_CASE_DEFINE(
+    XTEST_TEE_6013, xtest_tee_test_6013,
+    /* Title */
+    "Key usage in Persistent objects",
+    /* Short description */
+    "Short description ...",
+    /* Requirement IDs */
+    "TEE-??",
+    /* How to implement */
+    "Description of how to implement ..."
+);
diff --git a/host/xtest/xtest_main.c b/host/xtest/xtest_main.c
index 4f1beb5..91e1eba 100644
--- a/host/xtest/xtest_main.c
+++ b/host/xtest/xtest_main.c
@@ -64,6 +64,7 @@
 ADBG_SUITE_ENTRY(XTEST_TEE_6011, NULL)
 #endif
 ADBG_SUITE_ENTRY(XTEST_TEE_6012, NULL)
+ADBG_SUITE_ENTRY(XTEST_TEE_6013, NULL)
 ADBG_SUITE_ENTRY(XTEST_TEE_7001, NULL)
 /* FVP    ADBG_SUITE_ENTRY(XTEST_TEE_7002, NULL) */
 ADBG_SUITE_ENTRY(XTEST_TEE_7003, NULL)
diff --git a/host/xtest/xtest_test.h b/host/xtest/xtest_test.h
index 06d821f..0863fa5 100644
--- a/host/xtest/xtest_test.h
+++ b/host/xtest/xtest_test.h
@@ -59,6 +59,7 @@
 ADBG_CASE_DECLARE(XTEST_TEE_6011);
 #endif
 ADBG_CASE_DECLARE(XTEST_TEE_6012);
+ADBG_CASE_DECLARE(XTEST_TEE_6013);
 ADBG_CASE_DECLARE(XTEST_TEE_7001);
 ADBG_CASE_DECLARE(XTEST_TEE_7002);
 ADBG_CASE_DECLARE(XTEST_TEE_7003);
diff --git a/ta/storage/include/storage.h b/ta/storage/include/storage.h
index 0dd8e16..a736197 100644
--- a/ta/storage/include/storage.h
+++ b/ta/storage/include/storage.h
@@ -32,7 +32,8 @@
 
 TEE_Result ta_storage_cmd_open(uint32_t param_types, TEE_Param params[4]);
 TEE_Result ta_storage_cmd_create(uint32_t param_types, TEE_Param params[4]);
-TEE_Result ta_storage_cmd_create_overwrite(uint32_t param_types, TEE_Param params[4]);
+TEE_Result ta_storage_cmd_create_overwrite(uint32_t param_types,
+					   TEE_Param params[4]);
 TEE_Result ta_storage_cmd_close(uint32_t param_types, TEE_Param params[4]);
 TEE_Result ta_storage_cmd_read(uint32_t param_types, TEE_Param params[4]);
 TEE_Result ta_storage_cmd_write(uint32_t param_types, TEE_Param params[4]);
@@ -45,5 +46,7 @@
 TEE_Result ta_storage_cmd_reset_enum(uint32_t param_types, TEE_Param params[4]);
 TEE_Result ta_storage_cmd_start_enum(uint32_t param_types, TEE_Param params[4]);
 TEE_Result ta_storage_cmd_next_enum(uint32_t param_types, TEE_Param params[4]);
+TEE_Result ta_storage_cmd_key_in_persistent(uint32_t param_types,
+					    TEE_Param params[4]);
 
 #endif /*STORAGE_H */
diff --git a/ta/storage/include/ta_storage.h b/ta/storage/include/ta_storage.h
index e322a99..ecaf541 100644
--- a/ta/storage/include/ta_storage.h
+++ b/ta/storage/include/ta_storage.h
@@ -46,5 +46,6 @@
 #define TA_STORAGE_CMD_START_ENUM     12
 #define TA_STORAGE_CMD_NEXT_ENUM      13
 #define TA_STORAGE_CMD_CREATE_OVERWRITE	14
+#define TA_STORAGE_CMD_KEY_IN_PERSISTENT 15
 
 #endif /*TA_SKELETON_H */
diff --git a/ta/storage/storage.c b/ta/storage/storage.c
index 599a5be..2be171e 100644
--- a/ta/storage/storage.c
+++ b/ta/storage/storage.c
@@ -28,6 +28,7 @@
 #include "storage.h"
 
 #include <tee_api.h>
+#include <trace.h>
 
 #define ASSERT_PARAM_TYPE(pt) \
 do { \
@@ -270,3 +271,120 @@
 					   params[2].memref.buffer,
 					   &params[2].memref.size);
 }
+
+static TEE_Result check_obj(TEE_ObjectInfo *o1, TEE_ObjectInfo *o2)
+{
+	if ((o1->objectType != o2->objectType) ||
+	    (o1->keySize != o2->keySize) ||
+	    (o1->maxKeySize != o2->maxKeySize) ||
+	    (o1->objectUsage != o2->objectUsage))
+		return TEE_ERROR_GENERIC;
+	return TEE_SUCCESS;
+}
+
+TEE_Result ta_storage_cmd_key_in_persistent(uint32_t param_types,
+					    TEE_Param params[4])
+{
+	TEE_Result result = TEE_SUCCESS;
+	TEE_ObjectHandle transient_key = (TEE_ObjectHandle)NULL;
+	TEE_ObjectHandle persistent_key = (TEE_ObjectHandle)NULL;
+	TEE_ObjectHandle key = (TEE_ObjectHandle)NULL;
+	TEE_OperationHandle encrypt_op = (TEE_OperationHandle)NULL;
+	TEE_ObjectInfo keyInfo;
+	TEE_ObjectInfo keyInfo2;
+	TEE_ObjectInfo keyInfo3;
+	uint32_t alg = TEE_ALG_AES_CBC_NOPAD;
+	void *IV = NULL;
+	size_t IVlen = 16;
+	size_t key_size = 256;
+	uint32_t objectID = 1;
+	uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
+			 TEE_DATA_FLAG_ACCESS_WRITE |
+			 TEE_DATA_FLAG_ACCESS_WRITE_META |
+			 TEE_DATA_FLAG_SHARE_READ |
+			 TEE_DATA_FLAG_SHARE_WRITE;
+
+	(void)param_types;
+	(void)params;
+
+	result = TEE_AllocateTransientObject(TEE_TYPE_AES, key_size,
+					     &transient_key);
+	if (result != TEE_SUCCESS) {
+		EMSG("Failed to Allocate transient object handle : 0x%x",
+		     result);
+		goto cleanup1;
+	}
+
+	result = TEE_GenerateKey(transient_key, key_size, NULL, 0);
+	if (result != TEE_SUCCESS) {
+		EMSG("Failed to generate a transient key: 0x%x", result);
+		goto cleanup2;
+	}
+
+	TEE_GetObjectInfo1(transient_key, &keyInfo);
+	result = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE,
+					    &objectID, sizeof(objectID),
+					    flags, transient_key, NULL, 0,
+					    &persistent_key);
+	if (result != TEE_SUCCESS) {
+		EMSG("Failed to create a persistent key: 0x%x", result);
+		goto cleanup2;
+	}
+
+	TEE_GetObjectInfo1(persistent_key, &keyInfo2);
+	result = check_obj(&keyInfo, &keyInfo2);
+	if (result != TEE_SUCCESS) {
+		EMSG("keyInfo and keyInfo2 are different");
+		goto cleanup2;
+	}
+
+	TEE_CloseObject(persistent_key);
+
+	result = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE,
+					  &objectID, sizeof(objectID),
+					  flags, &key);
+	if (result != TEE_SUCCESS) {
+		EMSG("Failed to open persistent key: 0x%x", result);
+		goto cleanup2;
+	}
+
+	TEE_GetObjectInfo(key, &keyInfo3);
+	result = check_obj(&keyInfo3, &keyInfo2);
+	if (result != TEE_SUCCESS) {
+		EMSG("keyInfo2 and keyInfo3 are different");
+		goto cleanup2;
+	}
+
+	result = TEE_AllocateOperation(&encrypt_op, alg, TEE_MODE_ENCRYPT,
+				       keyInfo3.maxObjectSize);
+	if (result != TEE_SUCCESS) {
+		EMSG("Failed to allocate an operation: 0x%x", result);
+		goto cleanup3;
+	}
+
+	result = TEE_SetOperationKey(encrypt_op, key);
+	if (result != TEE_SUCCESS) {
+		EMSG("Failed to set operation key: 0x%x", result);
+		goto cleanup4;
+	}
+
+	IV = TEE_Malloc(IVlen, 0);
+	if (!IV) {
+		EMSG("Out of memory for IV.");
+		result = TEE_ERROR_OUT_OF_MEMORY;
+		goto cleanup4;
+	}
+
+	TEE_CipherInit(encrypt_op, IV, IVlen);
+	TEE_Free(IV);
+
+cleanup4:
+	TEE_FreeOperation(encrypt_op);
+cleanup3:
+	TEE_CloseAndDeletePersistentObject1(key);
+cleanup2:
+	TEE_FreeTransientObject(transient_key);
+cleanup1:
+	return result;
+}
+
diff --git a/ta/storage/ta_entry.c b/ta/storage/ta_entry.c
index 5a55fed..d2efd18 100644
--- a/ta/storage/ta_entry.c
+++ b/ta/storage/ta_entry.c
@@ -115,6 +115,9 @@
 	case TA_STORAGE_CMD_NEXT_ENUM:
 		return ta_storage_cmd_next_enum(nParamTypes, pParams);
 
+	case TA_STORAGE_CMD_KEY_IN_PERSISTENT:
+		return ta_storage_cmd_key_in_persistent(nParamTypes, pParams);
+
 	default:
 		return TEE_ERROR_BAD_PARAMETERS;
 	}