#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
}
}
+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) {
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;
+}