Support init/update/final for AES GCM & getting max chunk size 58/296258/36
authorDongsun Lee <ds73.lee@samsung.com>
Wed, 2 Aug 2023 06:17:51 +0000 (15:17 +0900)
committerDong Sun Lee <ds73.lee@samsung.com>
Thu, 10 Aug 2023 04:39:51 +0000 (04:39 +0000)
Change-Id: Id0251e4803e7754b7c298924d4b76844633fd1b2

ta/CMakeLists.txt
ta/include/cipher_ctx_list.h [new file with mode: 0644]
ta/include/cmd_exec.h
ta/src/cipher_ctx_list.c [new file with mode: 0644]
ta/src/cmd_exec.c
ta/src/km_ta.c

index 0df5f9e91a5403fb3048959363d0d17dcf37279d..b3cbb9477b89fba06a3ddc97a12ac3cdbf245951 100644 (file)
@@ -24,6 +24,7 @@ SET(TARGET_KEY_MANAGER_TA 00000000-0000-0000-0000-666666555555.elf)
 ############# TA #############
 
 SET(KEY_MANAGER_TA_SOURCES
+    ${KEY_MANAGER_TA_PATH}/src/cipher_ctx_list.c
     ${KEY_MANAGER_TA_PATH}/src/cmd_exec.c
     ${KEY_MANAGER_TA_PATH}/src/crypto_asymmetric.c
     ${KEY_MANAGER_TA_PATH}/src/crypto_auth.c
diff --git a/ta/include/cipher_ctx_list.h b/ta/include/cipher_ctx_list.h
new file mode 100644 (file)
index 0000000..3c0ca14
--- /dev/null
@@ -0,0 +1,17 @@
+
+#include <internal.h>
+
+typedef struct listNode
+{
+    struct listNode *next;
+    uint32_t id; // random value
+    uint32_t last_access; // System Time in second
+    TEE_OperationHandle oper;
+    uint32_t tag_len_bits;
+}listNode;
+
+#define MAX_CTX_TIMEOUT 600 // 10 minutes
+
+listNode *ctxl_read_node_id(uint32_t id);
+listNode *ctxl_add_last_node(TEE_OperationHandle oper, uint32_t tag_len_bits);
+void ctxl_delete_node_id(uint32_t id);
index 684721f0d2084d9d4ccd171d4bcc6026c2247aba..6767dc06294cf790a6edf43e6c9234513edc4635 100644 (file)
@@ -60,4 +60,16 @@ TEE_Result KM_ExecCmdImportWrappedKey(TEE_Param param[4]);
 
 TEE_Result KM_ExecCmdExportWrappedKey(TEE_Param param[4]);
 
+TEE_Result KM_ExecCmdCipherInit(TEE_Param param[4]);
+
+TEE_Result KM_ExecCmdCipherInitAad(TEE_Param param[4]);
+
+TEE_Result KM_ExecCmdCipherUpdate(TEE_Param param[4]);
+
+TEE_Result KM_ExecCmdCipherFinalize(TEE_Param param[4]);
+
+TEE_Result KM_ExecCmdCipherCleanup(TEE_Param param[4]);
+
+TEE_Result KM_ExecCmdGetMaxChunkSize(TEE_Param param[4]);
+
 #endif // __CMD_EXEC_H__
diff --git a/ta/src/cipher_ctx_list.c b/ta/src/cipher_ctx_list.c
new file mode 100644 (file)
index 0000000..c257c92
--- /dev/null
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tee_internal_api.h>
+#include <cipher_ctx_list.h>
+#include <log.h>
+
+static listNode head = {NULL, 0, 0, TEE_HANDLE_NULL, 0};
+
+static void set_time(listNode *node)
+{
+    TEE_Time now;
+    TEE_GetSystemTime(&now);
+    node->last_access = now.seconds;
+}
+
+static void set_last_access(listNode *node)
+{
+    TEE_Time now;
+    TEE_GetSystemTime(&now);
+    node->last_access = now.seconds;
+}
+
+static void free_node(listNode *node)
+{
+    TEE_FreeOperation(node->oper);
+
+    free(node);
+}
+
+static listNode *find_end_remove_expired()
+{
+    TEE_Time now;
+    listNode *prev = NULL;
+    listNode *cur = NULL;
+    listNode *to_remove = NULL;
+
+    prev = &head;  // skip checking for head node
+    cur = prev->next;
+
+    TEE_GetSystemTime(&now);
+
+    while (cur != NULL) {
+        if(now.seconds - cur->last_access > MAX_CTX_TIMEOUT) {
+            // remove expired next
+            to_remove = cur;
+            prev->next = cur->next;
+            // Remove key & operation...
+            free_node(to_remove);
+        } else {
+            prev = cur;
+        }
+        cur = cur->next;
+    }
+
+    return (prev);
+}
+
+listNode *ctxl_read_node_id(uint32_t id)
+{
+    listNode *cur;
+    cur = head.next; // skip head node
+
+    while (cur != NULL && cur->id != id) {
+        cur = cur->next;
+    }
+    if(cur == NULL) {
+        LOG("wrong data");
+        return NULL;
+    }
+
+    set_last_access(cur);
+
+    return (cur);
+}
+
+listNode *ctxl_add_last_node(TEE_OperationHandle oper, uint32_t tag_len_bits)
+{
+    listNode *end;
+
+    end = find_end_remove_expired();
+    listNode *newNode;
+    newNode = (listNode *) malloc(sizeof(listNode));
+    newNode->id = (uint32_t) oper; // Use the pointer of operation.
+    newNode->oper = oper;
+    newNode->tag_len_bits = tag_len_bits;
+    newNode->next = NULL;
+
+    set_time(newNode);
+
+    end->next = newNode;
+
+    return (newNode);
+}
+
+void ctxl_delete_node_id(uint32_t id)
+{
+    listNode *prev, *cur;
+
+    prev = &head;
+    cur = head.next;
+
+    while (cur != NULL && cur->id != id) {
+        prev = cur;
+        cur = cur->next;
+    }
+
+    if(cur == NULL) { // Not Found
+        return ;
+    }
+
+    prev->next = cur->next;
+
+    free_node(cur);
+}
index 09b10af2c765ae183ccd40c8dfd5bdbf2ef5dc63..6a99e0f703973f21b8655694dcf63b630c7ef840 100644 (file)
@@ -35,6 +35,7 @@
 #include <crypto_padding.h>
 #include <km_serialization.h>
 #include <cmd_exec.h>
+#include <cipher_ctx_list.h>
 #include <log.h>
 
 // random value to mark unsupported algorithm
@@ -63,6 +64,16 @@ static uint32_t KM_Cmd2TeeMode(int cmd)
        }
 }
 
+static uint32_t KM_EncFlag2TeeMode(int cmd)
+{
+       switch (cmd) {
+       case 0: return TEE_MODE_DECRYPT;
+       case 1: return TEE_MODE_ENCRYPT;
+       default: return 0;
+       }
+}
+
+
 static uint32_t KM_Algo2TeeAlgo(int algo)
 {
        switch (algo) {
@@ -2551,3 +2562,324 @@ TEE_Result KM_ExecCmdDestroyData(TEE_Param param[4])
        KM_DestroyData(objectId.data, objectId.data_size);
        return TEE_SUCCESS;
 }
+
+TEE_Result KM_ExecCmdCipherInit(TEE_Param param[4])
+{
+       // Only Support AES GCM for now.
+       TEE_Result ret = TEE_SUCCESS;
+       TEE_ObjectHandle key = TEE_HANDLE_NULL;
+       TEE_OperationHandle op = TEE_HANDLE_NULL;
+
+       KM_PwdData pwd_data;
+       uint32_t with_pwd = 0;
+       KM_BinaryData iv = {0, NULL};
+       KM_BinaryData key_id = {0, NULL};
+       KM_BinaryData aad = {0, NULL};
+       uint32_t tag_len_bits = 0;
+       uint32_t algo = 0;
+       uint32_t encrypt = 0;
+       uint32_t tee_algo = 0;
+       uint32_t tee_mode = 0;
+       listNode *new_ctx = NULL;
+
+       void *in_buffer = param[1].memref.buffer;
+       uint32_t in_size_guard = param[1].memref.size;
+
+       algo = param[0].value.a;
+       encrypt = param[0].value.b;
+
+       if(KM_DeserializeFlagAndPw(&in_buffer, &in_size_guard, &with_pwd, &pwd_data)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &iv)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &key_id)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &aad)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       if (KM_DeserializeFlag(&in_buffer, &in_size_guard, &tag_len_bits)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       // open key and (if needed) decrypt it
+       if (with_pwd) {
+               ret = KM_DecryptKey(key_id.data, key_id.data_size, &pwd_data, &key);
+       } else {
+               ret = KM_OpenKey(key_id.data, key_id.data_size, &key);
+       }
+       if (TEE_SUCCESS != ret) {
+               LOG("Failed to open key: %x", ret);
+               goto clean;
+       }
+
+       // Create Operation
+       tee_algo = KM_Algo2TeeAlgo(algo);
+       tee_mode = KM_EncFlag2TeeMode(encrypt);
+
+       ret = KM_CreateOperation(key, tee_algo, tee_mode, &op);
+       if (TEE_SUCCESS != ret) {
+               LOG("Failed to create auth crypto operation: %x", ret);
+               goto clean;
+       }
+
+       // Do Cipher Init
+       ret = TEE_AEInit(op, iv.data, iv.data_size, tag_len_bits, 0, 0);
+       if (TEE_SUCCESS != ret) {
+               LOG("TEE_AEInit failed with error=%x.", ret);
+               goto clean;
+       }
+
+       if (aad.data != NULL && aad.data_size > 0) {
+               TEE_AEUpdateAAD(op, aad.data, aad.data_size);
+       }
+
+       // Store Operation and Get Operation ID
+       new_ctx = ctxl_add_last_node(op, tag_len_bits);
+
+       // Send to REE
+       param[0].value.b = new_ctx->id;
+
+clean:
+       if (key != TEE_HANDLE_NULL)
+               TEE_CloseObject(key);
+       if (ret != TEE_SUCCESS && op != TEE_HANDLE_NULL)
+               TEE_FreeOperation(op);
+       return ret;
+}
+
+TEE_Result KM_ExecCmdCipherInitAad(TEE_Param param[4])
+{
+       TEE_Result ret = TEE_SUCCESS;
+       TEE_OperationHandle op = TEE_HANDLE_NULL;
+
+       KM_BinaryData aad = {0, NULL};
+       uint32_t op_id = 0;
+       listNode *ctx = NULL;
+
+       void *in_buffer = param[1].memref.buffer;
+       uint32_t in_size_guard = param[1].memref.size;
+
+       op_id = param[0].value.a;
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &aad)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       // Get Operation
+       ctx = ctxl_read_node_id(op_id);
+       if(ctx == NULL) {
+               LOG("Invalid Operation ID. OP_ID=%x", op_id);
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+       op = ctx->oper;
+
+       // Update AAD
+       if (aad.data == NULL || aad.data_size == 0) {
+               LOG("Null or Zero sized AAD Input");
+               goto clean; // skip TEE_AEUpdateAAD
+       }
+
+       TEE_AEUpdateAAD(op, aad.data, aad.data_size);
+
+clean:
+       return ret;
+
+}
+
+TEE_Result KM_ExecCmdCipherUpdate(TEE_Param param[4])
+{
+       TEE_Result ret = TEE_SUCCESS;
+       TEE_OperationHandle op = TEE_HANDLE_NULL;
+
+       KM_BinaryData data = {0, NULL};
+       uint32_t op_id = 0;
+       listNode *ctx = NULL;
+       KM_BinaryData output = {0, NULL};
+
+       void *in_buffer = param[1].memref.buffer;
+       void *out_buffer = param[2].memref.buffer;
+       uint32_t in_size_guard = param[1].memref.size;
+       uint32_t out_size_guard = param[2].memref.size;
+
+       op_id = param[0].value.a;
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &data)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       // Get Operation
+       ctx = ctxl_read_node_id(op_id);
+       if(ctx == NULL) {
+               LOG("Invalid Operation ID. OP_ID=%x", op_id);
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+       op = ctx->oper;
+
+       output.data_size = data.data_size + KM_ENCRYPTION_OVERHEAD;
+       output.data = malloc(output.data_size);
+       if (output.data == NULL) {
+               LOG("Failed to allocate buffer for output of KM_ExecCmdCipherUpdate()");
+               ret = TEE_ERROR_OUT_OF_MEMORY;
+               goto clean;
+       }
+
+       // Update Cipher
+       ret = TEE_AEUpdate(op, data.data, data.data_size, output.data, &output.data_size);
+       if( ret != TEE_SUCCESS) {
+               LOG("Failed in TEE_AEUpdate(). ret=%x", ret);
+               goto clean;
+       }
+
+       // Send output to REE
+       if (KM_Serialize(&out_buffer, &out_size_guard, output.data, output.data_size)) {
+               LOG("Error in serialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+       }
+
+clean:
+       if (output.data != NULL)
+               free(output.data);
+       return ret;
+}
+
+TEE_Result KM_ExecCmdCipherFinalize(TEE_Param param[4])
+{
+       TEE_Result ret = TEE_SUCCESS;
+       TEE_OperationHandle op = TEE_HANDLE_NULL;
+       TEE_OperationInfo op_info;
+
+       KM_BinaryData data = {0, NULL}; // includes only tag for aes gcm decryption
+       uint32_t op_id = 0;
+    uint32_t tag_len_bytes;
+       listNode *ctx = NULL;
+       KM_BinaryData output = {0, NULL};
+       KM_BinaryData dummy_output = {0, NULL};
+
+       void *in_buffer = param[1].memref.buffer;
+       void *out_buffer = param[2].memref.buffer;
+       uint32_t in_size_guard = param[1].memref.size;
+       uint32_t out_size_guard = param[2].memref.size;
+
+       op_id = param[0].value.a;
+
+       if (KM_DeserializeBinaryData(&in_buffer, &in_size_guard, &data)) {
+               LOG("Error in deserialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+       // Get Operation
+       ctx = ctxl_read_node_id(op_id);
+       if(ctx == NULL) {
+               LOG("Invalid Operation ID. OP_ID=%x", op_id);
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+       op = ctx->oper;
+       TEE_GetOperationInfo(op, &op_info);
+       tag_len_bytes = (ctx->tag_len_bits + 7) / 8;
+
+       // Finalize Cipher
+       if (op_info.mode == TEE_MODE_DECRYPT) {
+               if (data.data_size != tag_len_bytes){
+                       LOG("Invalid Tag Lenghth. expected=%d, actual=%d", tag_len_bytes, data.data_size);
+                       ret = TEE_ERROR_BAD_PARAMETERS;
+                       goto clean;
+               }
+               ret = TEE_AEDecryptFinal(op, NULL, 0,
+                                                               dummy_output.data, &dummy_output.data_size,
+                                                               data.data, data.data_size);
+               if (ret == TEE_SUCCESS && dummy_output.data_size != 0) {
+                       LOG("The output size of TEE_AEDecryptFinal() should be zero, but not. output_size=%d",
+                                       dummy_output.data_size);
+                       ret = TEE_ERROR_GENERIC;
+                       goto clean;
+               }
+               if (ret == TEE_ERROR_MAC_INVALID)
+                       ret = TEE_ERROR_BAD_PARAMETERS;
+       } else {
+               if(data.data_size != 0) {
+                       LOG("Invalid Input in KM_ExecCmdCipherFinalize(). input data should be 0. data_size=%d", data.data_size);
+                       ret = TEE_ERROR_BAD_PARAMETERS;
+                       goto clean;
+               }
+               output.data_size = tag_len_bytes;
+               output.data = malloc(output.data_size);
+               if (output.data == NULL) {
+                       LOG("Failed to allocate buffer for tag of KM_ExecCmdCipherFinalize()");
+                       ret = TEE_ERROR_OUT_OF_MEMORY;
+                       goto clean;
+               }
+               ret = TEE_AEEncryptFinal(op, NULL, 0,
+                                                               dummy_output.data, &dummy_output.data_size,
+                                                               output.data, &output.data_size);
+       }
+
+
+       if (TEE_SUCCESS != ret) {
+               LOG("TEE_AEDecryptFinal or TEE_AEEncryptFinal failed with error=%x.", ret);
+               goto clean;
+       }
+
+       // Send output to REE
+       if (KM_Serialize(&out_buffer, &out_size_guard, output.data, output.data_size)) {
+               LOG("Error in serialization");
+               ret = TEE_ERROR_BAD_PARAMETERS;
+               goto clean;
+       }
+
+clean:
+       // Remove Stored Operation. Operation & Key will be freed too.
+       ctxl_delete_node_id(op_id);
+       if (dummy_output.data != NULL)
+               free(dummy_output.data);
+       if (output.data != NULL)
+               free(output.data);
+       return ret;
+}
+
+TEE_Result KM_ExecCmdCipherCleanup(TEE_Param param[4])
+{
+       TEE_Result ret = TEE_SUCCESS;
+       uint32_t op_id = 0;
+
+       op_id = param[0].value.a;
+
+       ctxl_delete_node_id(op_id);
+
+       return ret;
+}
+
+TEE_Result KM_ExecCmdGetMaxChunkSize(TEE_Param param[4])
+{
+       TEE_Result ret = TEE_SUCCESS;
+       uint32_t max_chunk_size = 4 * 1024;
+
+       // Return to REE
+       param[0].value.b = max_chunk_size;
+
+       return ret;
+}
index 2f7d987747b824d3b06782d780b455d1062c7d6b..5e7772f39d05369b06b8845fb5814fd4829f7a70 100644 (file)
@@ -188,6 +188,36 @@ TEE_Result TA_InvokeCommandEntryPoint(
                ret = KM_ExecCmdExportWrappedKey(param);
                break;
        }
+       case CMD_CIPHER_INIT: {
+               LOGD("!!! Initializing cipher context !!!");
+               ret = KM_ExecCmdCipherInit(param);
+               break;
+       }
+       case CMD_CIPHER_INIT_AAD: {
+               LOGD("!!! Supply another AAD chunk for the context !!!");
+               ret = KM_ExecCmdCipherInitAad(param);
+               break;
+       }
+       case CMD_CIPHER_UPDATE: {
+               LOGD("!!! Supply data for cipher operation !!!");
+               ret = KM_ExecCmdCipherUpdate(param);
+               break;
+       }
+       case CMD_CIPHER_FINALIZE: {
+               LOGD("!!! Finish cipher operation !!!");
+               ret = KM_ExecCmdCipherFinalize(param);
+               break;
+       }
+       case CMD_CIPHER_CLEANUP: {
+               LOGD("!!! Clean up cipher context!!!");
+               ret = KM_ExecCmdCipherCleanup(param);
+               break;
+       }
+       case CMD_GET_MAX_CHUNK_SIZE: {
+               LOGD("!!! Get Max Chunk Size!!!");
+               ret = KM_ExecCmdGetMaxChunkSize(param);
+               break;
+       }
        default: {
                LOG("Unknown commandID=%d.", commandID);
                ret = TEE_ERROR_BAD_PARAMETERS;