commit 0c1ec145aac7d3f646b2bfabfb049265377faa2c Author: djmil Date: Thu Mar 21 22:12:03 2024 +0100 initial commit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2c63510 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,62 @@ +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive +RUN apt update && apt upgrade -y +RUN apt install -y \ + adb \ + acpica-tools \ + autoconf \ + automake \ + bc \ + bison \ + build-essential \ + ccache \ + cpio \ + cscope \ + curl \ + device-tree-compiler \ + e2tools \ + expect \ + fastboot \ + flex \ + ftp-upload \ + gdisk \ + git \ + libattr1-dev \ + libcap-ng-dev \ + libfdt-dev \ + libftdi-dev \ + libglib2.0-dev \ + libgmp3-dev \ + libhidapi-dev \ + libmpc-dev \ + libncurses5-dev \ + libpixman-1-dev \ + libslirp-dev \ + libssl-dev \ + libtool \ + libusb-1.0-0-dev \ + make \ + mtools \ + netcat \ + ninja-build \ + python3-cryptography \ + python3-pip \ + python3-pyelftools \ + python3-serial \ + python-is-python3 \ + rsync \ + swig \ + unzip \ + uuid-dev \ + wget \ + xdg-utils \ + xterm \ + xz-utils \ + zlib1g-dev +RUN curl https://storage.googleapis.com/git-repo-downloads/repo > /bin/repo && chmod a+x /bin/repo +RUN mkdir /optee +WORKDIR /optee +RUN repo init -u https://github.com/OP-TEE/manifest.git -m qemu_v8.xml && repo sync -j10 +WORKDIR /optee/build +RUN make -j2 toolchains +RUN make -j$(nproc) check \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d248a6a --- /dev/null +++ b/README.md @@ -0,0 +1,82 @@ +This project provides a simple PoC implementation of a Secure Storage on top of [OP-TEE](https://optee.readthedocs.io/en/latest/general/about.html) TrustZone based technology. + +# Main functionality + +The project consists of two modules: Trusted Application and Normal World client. + +## Trusted Application + +1. Generate RSA key pair. +2. Serialize / Deserialize RSA key pair into Secure Storage for use across sessions. Access to multiple RSA key pairs is implemented with help of TAG identifiers. +3. A special run-time provided PIN is used for further RSA key pair protection. Provided PIN is used by Trusted Application to derive SessionKey, which is used for encryption / decryption of RSA key pair matherial stored in Secure Storage. +4. RSA key pair data is never exposed outside of Trusted Application. +5. Assuming that correct PIN is known, Client Application can use RSA key pair TAG to encrypt / decrypt arbitrary data. + +## Normal World client application + +1. Provides functional demo for APIs exposed by Trusted Application. + +# Build instructions + +Usually, access to ARM TrustZone powered device is necessary to see GP-TEE based APIs in action. This project benefits heavily from virtualization techniques like Docker and Qemu. + +## 1 Prepare build environment + +Run `build-docker.sh` script. + +This operation might take several hours to finish. It will create Ubuntu based container, will install all necessary build tools and dependancies. Lastly, it will `git clone` OP-TEE repository with ARMv8 build flavour. Check `Dockerfile` for actual list of performed actions. + +## 2 Execute build environment + +Use `run-docker.sh` script. The script will: +- map src folder `bliq_storage` inside build environment +- use X11 window forwarding technique, to map two `cli` named **Normal World** and **Secure World** from Docker container onto your host OS + +If all went well, you will end up inside an instance of Ubuntu dev environment with `cli` interface similar to `root@80e6b6f27bef:/optee/build#`. + +### X11 window forwarding + +Use [XQuartz](https://www.xquartz.org/) to enable x11 window forwarding on [mac](https://gist.github.com/sorny/969fe55d85c9b0035b0109a31cbcb088). + +> [!NOTE] Be ware +> You will always have to run `xhost +` after a restart of X11 as this is not a persistent setting. + +## 3 Build and run demo application + +Typing `make run` in `/optee/build`. Will start build for Secure and Normal world parts of OP-TEE OS. After successful build `qemu` emulator will be executed. Press `c` to proceed with virtual device execution. On a first run you might need to type `boot` in **Normal World** console to start boot process. + +After the boot finishes, use **Normal World** console window to login as `root`. Then simply type `bliq_storage` to execute demo app, which was build directly from sources. + +Other OP-TEE [demo applications](https://github.com/linaro-swg/optee_examples) are also available. Use *tab-key* to assist with typing. + +# Source code overview + +## `bliq_storege\ta` + +This folder contains sources for the Trusted Part of `Bliq Storage` application. Check header files to explore high level API exposed by project submodules. + +### `bliq_storage_ta.c` + +Main entry point for the Trusted Application. Provides high level implementation for the main commands: +- Create Key +- Delete Key +- Check Key +- Encrypt +- Decrypt + +It is also worth mentioning, that PIN-derived AES key (which is used for RSA key pair data encryption) lives in Session context, see `TA_OpenSessionEntryPoint()` + +### `operations.c` + +Handles AES PIN derivation API, as well as AES encryption / decryption functions for RSA key pair protection. + +### `key_pair.c` + +Incapsulates set of APIs of underlined GP-TEE APIs, necessary for RSA key pair creating and usage as a handy *trunsient* object. It also provides endpoints for RSA key-pair encryption and decryption of arbitrary data. + +Two functions `kp_serialize()` and `kp_deserilize()` might be seen as the sole `hard` of an entire project. Since they are used for *storing / re-storing* RSA key pair data* into / from* a flat buffer. The whole application might be seen as a set of *derivative / supportive* operations build *around / on top of* these two functions. + +## `bliq_storage/host/main.c` + +A simple TZ client application, showcasing communication between Normal World and Trusted World applications. A particular use case implementation of APIs defined by `bliq_storage\ta\include\bliq_storage_ta.h` + diff --git a/bliq_storage/Android.mk b/bliq_storage/Android.mk new file mode 100644 index 0000000..7ad0963 --- /dev/null +++ b/bliq_storage/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_CFLAGS += -DANDROID_BUILD +LOCAL_CFLAGS += -Wall + +LOCAL_SRC_FILES += host/main.c + +LOCAL_C_INCLUDES := $(LOCAL_PATH)/ta/include + +LOCAL_SHARED_LIBRARIES := libteec +LOCAL_MODULE := bliq_storage +LOCAL_VENDOR_MODULE := true +LOCAL_MODULE_TAGS := optional +include $(BUILD_EXECUTABLE) + +include $(LOCAL_PATH)/ta/Android.mk diff --git a/bliq_storage/CMakeLists.txt b/bliq_storage/CMakeLists.txt new file mode 100644 index 0000000..5d8dd77 --- /dev/null +++ b/bliq_storage/CMakeLists.txt @@ -0,0 +1,13 @@ +project (bliq_storage C) + +set (SRC host/main.c) + +add_executable (${PROJECT_NAME} ${SRC}) + +target_include_directories(${PROJECT_NAME} + PRIVATE ta/include + PRIVATE include) + +target_link_libraries (${PROJECT_NAME} PRIVATE teec) + +install (TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/bliq_storage/Makefile b/bliq_storage/Makefile new file mode 100644 index 0000000..dfa4f8b --- /dev/null +++ b/bliq_storage/Makefile @@ -0,0 +1,15 @@ +export V ?= 0 + +# If _HOST or _TA specific compilers are not specified, then use CROSS_COMPILE +HOST_CROSS_COMPILE ?= $(CROSS_COMPILE) +TA_CROSS_COMPILE ?= $(CROSS_COMPILE) + +.PHONY: all +all: + $(MAKE) -C host CROSS_COMPILE="$(HOST_CROSS_COMPILE)" --no-builtin-variables + $(MAKE) -C ta CROSS_COMPILE="$(TA_CROSS_COMPILE)" LDFLAGS="" + +.PHONY: clean +clean: + $(MAKE) -C host clean + $(MAKE) -C ta clean diff --git a/bliq_storage/host/Makefile b/bliq_storage/host/Makefile new file mode 100644 index 0000000..d3cba8f --- /dev/null +++ b/bliq_storage/host/Makefile @@ -0,0 +1,28 @@ +CC ?= $(CROSS_COMPILE)gcc +LD ?= $(CROSS_COMPILE)ld +AR ?= $(CROSS_COMPILE)ar +NM ?= $(CROSS_COMPILE)nm +OBJCOPY ?= $(CROSS_COMPILE)objcopy +OBJDUMP ?= $(CROSS_COMPILE)objdump +READELF ?= $(CROSS_COMPILE)readelf + +OBJS = main.o + +CFLAGS += -Wall -I../ta/include -I./include +CFLAGS += -I$(TEEC_EXPORT)/include +LDADD += -lteec -L$(TEEC_EXPORT)/lib + +BINARY = bliq_storage + +.PHONY: all +all: $(BINARY) + +$(BINARY): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $< $(LDADD) + +.PHONY: clean +clean: + rm -f $(OBJS) $(BINARY) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/bliq_storage/host/main.c b/bliq_storage/host/main.c new file mode 100644 index 0000000..f30926e --- /dev/null +++ b/bliq_storage/host/main.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017, Linaro Limited + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +/* OP-TEE TEE client API (built by optee_client) */ +#include + +/* TA API: UUID and command IDs */ +#include + +/* TEE resources */ +struct test_ctx { + TEEC_Context ctx; + TEEC_Session sess; +}; + +void open_tee_session( + struct test_ctx *ctx, + char *pin, size_t pin_len) +{ + TEEC_Operation op; + TEEC_UUID uuid = TA_BLIQ_STORAGE_UUID; + uint32_t origin; + TEEC_Result res; + + // Set session PIN + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); + + op.params[0].tmpref.buffer = pin; + op.params[0].tmpref.size = pin_len; + + /* Initialize a context connecting us to the TEE */ + res = TEEC_InitializeContext(NULL, &ctx->ctx); + if (res != TEEC_SUCCESS) + errx(1, "TEEC_InitializeContext failed with code 0x%x", res); + + /* Open a session with the TA */ + res = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid, + TEEC_LOGIN_PUBLIC, NULL, &op, &origin); + if (res != TEEC_SUCCESS) + errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x", + res, origin); +} + +void close_tee_session(struct test_ctx *ctx) +{ + TEEC_CloseSession(&ctx->sess); + TEEC_FinalizeContext(&ctx->ctx); +} + +TEEC_Result create_key( + struct test_ctx *ctx, + char *id) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + size_t id_len = strlen(id); + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES( + TEEC_MEMREF_TEMP_INPUT, + TEEC_NONE, + TEEC_NONE, + TEEC_NONE); + + op.params[0].tmpref.buffer = id; + op.params[0].tmpref.size = id_len; + + res = TEEC_InvokeCommand( + &ctx->sess, + TA_BLIQ_STORAGE_CMD_CREATE_KEY, + &op, &origin); + + switch (res) { + case TEEC_SUCCESS: + break; + default: + printf("Command TA_BLIQ_STORAGE_CMD_CREATE_KEY failed: 0x%x / %u\n", res, origin); + } + + return res; +} + +TEEC_Result check_key( + struct test_ctx *ctx, + char *id) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + size_t id_len = strlen(id); + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES( + TEEC_MEMREF_TEMP_INPUT, + TEEC_NONE, + TEEC_NONE, + TEEC_NONE); + + op.params[0].tmpref.buffer = id; + op.params[0].tmpref.size = id_len; + + res = TEEC_InvokeCommand( + &ctx->sess, + TA_BLIQ_STORAGE_CMD_CHECK_KEY, + &op, &origin); + + switch (res) { + case TEEC_SUCCESS: + case TEEC_ERROR_ITEM_NOT_FOUND: + break; + default: + printf("Command TA_BLIQ_STORAGE_CMD_CHECK_KEY failed: 0x%x / %u\n", res, origin); + } + + return res; +} + +TEEC_Result delete_key( + struct test_ctx *ctx, + char *id) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + size_t id_len = strlen(id); + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES( + TEEC_MEMREF_TEMP_INPUT, + TEEC_NONE, + TEEC_NONE, + TEEC_NONE); + + op.params[0].tmpref.buffer = id; + op.params[0].tmpref.size = id_len; + + res = TEEC_InvokeCommand( + &ctx->sess, + TA_BLIQ_STORAGE_CMD_DELETE_KEY, + &op, &origin); + + switch (res) { + case TEEC_SUCCESS: + case TEEC_ERROR_ITEM_NOT_FOUND: + break; + default: + printf("Command TA_BLIQ_STORAGE_CMD_DELETE_KEY failed: 0x%x / %u\n", res, origin); + } + + return res; +} + +TEEC_Result encrypt( + struct test_ctx *ctx, + char *id, + char *data, uint32_t data_len, + char *encr, uint32_t *encr_len + ) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + size_t id_len = strlen(id); + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES( + TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_INOUT, + TEEC_NONE); + + op.params[0].tmpref.buffer = id; + op.params[0].tmpref.size = id_len; + + op.params[1].tmpref.buffer = data; + op.params[1].tmpref.size = data_len; + + op.params[2].tmpref.buffer = encr; + op.params[2].tmpref.size = *encr_len; + + res = TEEC_InvokeCommand(&ctx->sess, + TA_BLIQ_STORAGE_CMD_ENCRYPT, + &op, &origin); + + switch (res) { + case TEEC_SUCCESS: + *encr_len = op.params[2].tmpref.size; + break; + default: + printf("Command TA_BLIQ_STORAGE_CMD_ENCRYPT failed: 0x%x / %u\n", res, origin); + } + + return res; +} + +TEEC_Result decrypt( + struct test_ctx *ctx, + char *id, + char *encr, uint32_t encr_len, + char *decr, uint32_t *decr_len + ) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + size_t id_len = strlen(id); + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES( + TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_INOUT, + TEEC_NONE); + + op.params[0].tmpref.buffer = id; + op.params[0].tmpref.size = id_len; + + op.params[1].tmpref.buffer = encr; + op.params[1].tmpref.size = encr_len; + + op.params[2].tmpref.buffer = decr; + op.params[2].tmpref.size = *decr_len; + + res = TEEC_InvokeCommand(&ctx->sess, + TA_BLIQ_STORAGE_CMD_DECRYPT, + &op, &origin); + + switch (res) { + case TEEC_SUCCESS: + *decr_len = op.params[2].tmpref.size; + break; + default: + printf("Command TA_BLIQ_STORAGE_CMD_DECRYPT failed: 0x%x / %u\n", res, origin); + } + + return res; +} + + + +int main(void) +{ + struct test_ctx ctx; + char key_id[] = "key#1"; + char pin[6] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; // used to encrypt/decrypt key + + char data[] = "Test string for data encryption"; + + char encrypted_data[512]; + uint32_t encrypted_data_sz = sizeof(encrypted_data); + + char decrypted_data[512]; + uint32_t decrypted_data_sz = sizeof(decrypted_data); + + TEEC_Result res; + + printf("Prepare session with the TA\n"); + open_tee_session(&ctx, pin, sizeof(pin)); + + /* + * Check Create , read it, delete it. + */ + printf("\nCheck KeyID \"%s\"\n", key_id); + res = check_key( + &ctx, + key_id); + if (res == TEEC_ERROR_ITEM_NOT_FOUND) { + printf(" - KeyId was not found in TA secure storage, create new one\n"); + + res = create_key( + &ctx, + key_id); + if (res != TEEC_SUCCESS) + errx(1, "Unexpected status when creating key: 0x%x", res); + + printf(" - RSA keypair creation [OK]\n"); + printf(" - Run application one more time to test Encrypt / Decrypt APIs..\n"); + } + else if (res == TEEC_SUCCESS) { + printf(" - KeyId was found!\n"); + printf(" - Test Encrypt / Decrypt APIs..\n"); + + res = encrypt( + &ctx, + key_id, + data, sizeof(data), + encrypted_data, &encrypted_data_sz); + if (res != TEEC_SUCCESS) + errx(1, "Unexpected status during data encryption: 0x%x", res); + + printf(" -- encr_data: [%u] first 4 bytes: %02x:%02x:%02x:%02x\n", + encrypted_data_sz, encrypted_data[0], encrypted_data[1], encrypted_data[2], encrypted_data[3]); + + res = decrypt(&ctx, key_id, + encrypted_data, encrypted_data_sz, + decrypted_data, &decrypted_data_sz); + if (res != TEEC_SUCCESS) + errx(1, "Unexpected status during data decryption: 0x%x", res); + + printf(" -- orig_data: [%lu] '%s'\n -- decr_data: [%d] '%s'\n", + sizeof(data), data, + decrypted_data_sz, decrypted_data); + + printf(" - Encrypt / Decrypt APIs test [ok]\n"); + printf(" - Delete RSA keypair from secure storage\n"); + + res = delete_key( + &ctx, + key_id); + if (res != TEEC_SUCCESS) + errx(1, "Unexpected status during key delition: 0x%x", res); + } + + close_tee_session(&ctx); + return 0; +} diff --git a/bliq_storage/ta/Android.mk b/bliq_storage/ta/Android.mk new file mode 100644 index 0000000..3c4546f --- /dev/null +++ b/bliq_storage/ta/Android.mk @@ -0,0 +1,4 @@ +LOCAL_PATH := $(call my-dir) + +local_module := 0651d840-a91b-4b3f-a222-b68cd195231c.ta +include $(BUILD_OPTEE_MK) diff --git a/bliq_storage/ta/Makefile b/bliq_storage/ta/Makefile new file mode 100644 index 0000000..ba44b00 --- /dev/null +++ b/bliq_storage/ta/Makefile @@ -0,0 +1,13 @@ +CFG_TEE_TA_LOG_LEVEL ?= 2 +CFG_TA_OPTEE_CORE_API_COMPAT_1_1=y + +# The UUID for the Trusted Application +BINARY=0651d840-a91b-4b3f-a222-b68cd195231c + +-include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk + +ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) +clean: + @echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' + @echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' +endif diff --git a/bliq_storage/ta/bliq_storage_ta.c b/bliq_storage/ta/bliq_storage_ta.c new file mode 100644 index 0000000..b17fef8 --- /dev/null +++ b/bliq_storage/ta/bliq_storage_ta.c @@ -0,0 +1,560 @@ +#include +#include +#include +#include +#include "operations.h" +#include "key_pair.h" +#include + +static TEE_Result ss_read_object( + char *obj_id, uint32_t obj_id_sz, + void *buff, uint32_t *buff_sz +) +{ + TEE_Result res; + TEE_ObjectHandle object = NULL; + TEE_ObjectInfo object_info; + + res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, + obj_id, obj_id_sz, + TEE_DATA_FLAG_ACCESS_READ | + TEE_DATA_FLAG_SHARE_READ, + &object); + if (res != TEE_SUCCESS) { + EMSG("[ERR] ss_read_object(): Failed to open persistent object, res=0x%x", res); + goto exit; + } + + res = TEE_GetObjectInfo1( + object, + &object_info); + if (res != TEE_SUCCESS) { + EMSG("[ERR] ss_read_object(): Failed to get persistent object ibfo, res=0x%x", res); + goto exit; + } + + if (object_info.dataSize > *buff_sz) { + /* + * Provided buffer is too short. + * Return the expected size together with status "short buffer" + */ + *buff_sz = object_info.dataSize; + res = TEE_ERROR_SHORT_BUFFER; + goto exit; + } + + res = TEE_ReadObjectData( + object, + buff, object_info.dataSize, + buff_sz); + +exit: + if (object) + TEE_CloseObject(object); + return res; +} + +static TEE_Result get_key( + Session *session, + char *obj_id, uint32_t obj_id_sz, + TEE_ObjectHandle *kp) +{ + TEE_Result res; + + char *kp_serialized_buff = NULL; + uint32_t kp_serialized_buff_sz = 2048; + + char *kp_decrypted_buff = NULL; + uint32_t kp_decrypted_buff_sz = 2048; + + kp_serialized_buff = TEE_Malloc(kp_serialized_buff_sz, 0); + if (!kp_serialized_buff) + return TEE_ERROR_OUT_OF_MEMORY; + + res = ss_read_object( + obj_id, obj_id_sz, + kp_serialized_buff, &kp_serialized_buff_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: get_key(%s): Unable to read data from sec store: 0x%x", obj_id, res); + goto exit; + } + + kp_decrypted_buff = TEE_Malloc(kp_decrypted_buff_sz, 0); + if (!kp_decrypted_buff) + return TEE_ERROR_OUT_OF_MEMORY; + + res = so_decrypt( + session, + kp_serialized_buff, kp_serialized_buff_sz, + kp_decrypted_buff, &kp_decrypted_buff_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: get_key(%s): Unable to decrypt RSA key pair: 0x%x", obj_id, res); + goto exit; + } + + res = kp_deserialize( + kp_decrypted_buff, kp_decrypted_buff_sz, + kp); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: get_key(%s): Unable to deserialize RSA key pair: 0x%x", obj_id, res); + goto exit; + } + +exit: + TEE_Free(kp_serialized_buff); + TEE_Free(kp_decrypted_buff); + return res; +} + +/* + * TA API implementation + */ +static TEE_Result create_key( + Session *session, + uint32_t param_types, + TEE_Param params[4]) +{ + const uint32_t exp_param_types = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + TEE_ObjectHandle kp = NULL; + TEE_ObjectHandle object; + TEE_Result res; + char *obj_id = NULL; + size_t obj_id_sz; + uint32_t obj_data_flag; + + char *kp_serialized_buff = NULL; + uint32_t kp_serialized_buff_sz = 2048; + + char *kp_encrypted_buff = NULL; + uint32_t kp_encrypted_buff_sz = 2048; + + /* + * Safely get the invocation parameters + */ + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + obj_id_sz = params[0].memref.size; + obj_id = TEE_Malloc(obj_id_sz, 0); + if (!obj_id) + return TEE_ERROR_OUT_OF_MEMORY; + + TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); + + /* + * Generate RSA KeyPair + */ + res = kp_create(&kp); + if (res != TEE_SUCCESS) { + EMSG("Unable to create RSA key pair: 0x%08x", res); + goto exit; + } + + /* + * Serialize RSA KeyPair into external buffer + */ + kp_serialized_buff = TEE_Malloc(kp_serialized_buff_sz, 0); + if (!kp_serialized_buff) + return TEE_ERROR_OUT_OF_MEMORY; + + res = kp_serialize( + kp, + kp_serialized_buff, &kp_serialized_buff_sz); + if (res != TEE_SUCCESS) { + EMSG("Unable to serialize RSA key pair: 0x%08x", res); + goto exit; + } + + /* + * Encrypt serrialized RSA keypair buffer + */ + kp_encrypted_buff = TEE_Malloc(kp_encrypted_buff_sz, 0); + if (!kp_encrypted_buff) + return TEE_ERROR_OUT_OF_MEMORY; + + res = so_encrypt( + session, + kp_serialized_buff, kp_serialized_buff_sz, + kp_encrypted_buff, &kp_encrypted_buff_sz); + if (res != TEE_SUCCESS) { + EMSG("Unable to encrypt RSA key pair: 0x%08x", res); + goto exit; + } + + /* + * Create object in secure storage and fill it with encrypted RSA keypair + */ + obj_data_flag = + TEE_DATA_FLAG_ACCESS_READ | /* we can later read the oject */ + TEE_DATA_FLAG_ACCESS_WRITE | /* we can later write into the object */ + TEE_DATA_FLAG_ACCESS_WRITE_META | /* we can later destroy or rename the object */ + TEE_DATA_FLAG_OVERWRITE; /* destroy existing object of same ID */ + + res = TEE_CreatePersistentObject(TEE_STORAGE_PRIVATE, + obj_id, obj_id_sz, + obj_data_flag, + TEE_HANDLE_NULL, + NULL, 0, /* we may not fill it right now */ + &object); + if (res != TEE_SUCCESS) { + EMSG("TEE_CreatePersistentObject failed 0x%08x", res); + goto exit; + } + + res = TEE_WriteObjectData( + object, + kp_encrypted_buff, kp_encrypted_buff_sz); + if (res != TEE_SUCCESS) { + EMSG("TEE_WriteObjectData failed 0x%08x", res); + TEE_CloseAndDeletePersistentObject1(object); + } else { + TEE_CloseObject(object); + } + +exit: + TEE_Free(obj_id); + TEE_Free(kp_serialized_buff); + TEE_Free(kp_encrypted_buff); + + if (kp) + TEE_FreeTransientObject(kp); + return res; +} + +static TEE_Result check_key( + Session *session, + uint32_t param_types, + TEE_Param params[4]) +{ + const uint32_t exp_param_types = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + TEE_Result res; + TEE_ObjectHandle kp = NULL; + + char *obj_id; + uint32_t obj_id_sz; + + /* + * Safely get the invocation parameters + */ + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + obj_id_sz = params[0].memref.size; + obj_id = TEE_Malloc(obj_id_sz, 0); + if (!obj_id) + return TEE_ERROR_OUT_OF_MEMORY; + + TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); + EMSG("[DBG] check_key(): obj_id '%s'", obj_id); + + res = get_key( + session, + obj_id, obj_id_sz, + &kp); + if (res != TEE_SUCCESS) { + EMSG("[ERR] check_key(): Unable to obtain RSA keypair: 0x%x", res); + goto exit; + } + +exit: + TEE_Free(obj_id); + if (kp) + TEE_FreeTransientObject(kp); + + return res; +} + + +static TEE_Result delete_key( + uint32_t param_types, + TEE_Param params[4]) +{ + const uint32_t exp_param_types = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + TEE_ObjectHandle object; + TEE_Result res; + char *obj_id; + size_t obj_id_sz; + + /* + * Safely get the invocation parameters + */ + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + obj_id_sz = params[0].memref.size; + obj_id = TEE_Malloc(obj_id_sz, 0); + if (!obj_id) + return TEE_ERROR_OUT_OF_MEMORY; + + TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); + + /* + * Check object exists and delete it + */ + res = TEE_OpenPersistentObject(TEE_STORAGE_PRIVATE, + obj_id, obj_id_sz, + TEE_DATA_FLAG_ACCESS_READ | + TEE_DATA_FLAG_ACCESS_WRITE_META, /* we must be allowed to delete it */ + &object); + if (res != TEE_SUCCESS) { + EMSG("[ERR] Unable to open persistent object, res=0x%x", res); + TEE_Free(obj_id); + return res; + } + + TEE_CloseAndDeletePersistentObject1(object); + TEE_Free(obj_id); + + return res; +} + +static TEE_Result encrypt_data( + Session *session, + uint32_t param_types, + TEE_Param params[4]) +{ + const uint32_t exp_param_types = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE); + + TEE_Result res; + TEE_ObjectHandle kp = NULL; + + char *obj_id; + uint32_t obj_id_sz; + + char *data; + uint32_t data_sz; + + char *enc_data; + uint32_t enc_data_sz; + + /* + * Safely get the invocation parameters + */ + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + obj_id_sz = params[0].memref.size; + obj_id = TEE_Malloc(obj_id_sz, 0); + if (!obj_id) + return TEE_ERROR_OUT_OF_MEMORY; + + TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); + EMSG("[DBG] encrypt_data: obj_id '%s'", obj_id); + + data_sz = params[1].memref.size; + data = TEE_Malloc(data_sz, 0); + if (!data) + return TEE_ERROR_OUT_OF_MEMORY; + + TEE_MemMove(data, params[1].memref.buffer, data_sz); + EMSG("[DBG] encrypt_data: plain_data '%s'", data); + + res = get_key( + session, + obj_id, obj_id_sz, + &kp); + if (res != TEE_SUCCESS) { + EMSG("[ERR] encrypt_data(): Unable to obtain RSA keypair: 0x%x", res); + goto exit; + } + + // const char msg[] = "hello from kp_encrypt"; + // EMSG("[DBG] encrypt_data(): Return hardcoded string"); + + // TEE_MemMove(params[2].memref.buffer, msg, sizeof(msg)); + // params[2].memref.size = sizeof(msg); + // return res; + + enc_data = params[2].memref.buffer; + enc_data_sz = params[2].memref.size; + + res = kp_encrypt( + kp, + data, data_sz, + enc_data, &enc_data_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR] encrypt_data(): Unable to encryp data: 0x%x", res); + goto exit; + } + + // Encryption [OK] + // update output buffer size + params[2].memref.size = enc_data_sz; + +exit: + TEE_Free(obj_id); + TEE_Free(data); + if (kp) + TEE_FreeTransientObject(kp); + + return res; +} + +static TEE_Result decrypt_data( + Session *session, + uint32_t param_types, + TEE_Param params[4]) +{ + const uint32_t exp_param_types = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE); + + TEE_Result res; + TEE_ObjectHandle kp = NULL; + + char *obj_id; + uint32_t obj_id_sz; + + char *data; + uint32_t data_sz; + + char *dec_data; + uint32_t dec_data_sz; + + /* + * Safely get the invocation parameters + */ + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + obj_id_sz = params[0].memref.size; + obj_id = TEE_Malloc(obj_id_sz, 0); + if (!obj_id) + return TEE_ERROR_OUT_OF_MEMORY; + + TEE_MemMove(obj_id, params[0].memref.buffer, obj_id_sz); + EMSG("[DBG] decrypt_data: obj_id '%s'", obj_id); + + data_sz = params[1].memref.size; + data = TEE_Malloc(data_sz, 0); + if (!data) + return TEE_ERROR_OUT_OF_MEMORY; + + TEE_MemMove(data, params[1].memref.buffer, data_sz); + + res = get_key( + session, + obj_id, obj_id_sz, + &kp); + if (res != TEE_SUCCESS) { + EMSG("[ERR] decrypt_data(): Unable to obtain RSA keypair: 0x%x", res); + goto exit; + } + + dec_data = params[2].memref.buffer; + dec_data_sz = params[2].memref.size; + + res = kp_decrypt( + kp, + data, data_sz, + dec_data, &dec_data_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR] decrypt_data(): Unable to decryp data: 0x%x", res); + goto exit; + } + + // Decryption [OK] + // update output buffer size + params[2].memref.size = dec_data_sz; + +exit: + TEE_Free(obj_id); + TEE_Free(data); + if (kp) + TEE_FreeTransientObject(kp); + + return res; +} + +TEE_Result TA_CreateEntryPoint(void) +{ + /* Nothing to do */ + return TEE_SUCCESS; +} + +void TA_DestroyEntryPoint(void) +{ + /* Nothing to do */ +} + +TEE_Result TA_OpenSessionEntryPoint( + uint32_t param_types, + TEE_Param params[4], + void **ctx) +{ + const uint32_t exp_param_types = TEE_PARAM_TYPES( + TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + /* + * Safely get the invocation parameters + */ + if (param_types != exp_param_types) + return TEE_ERROR_BAD_PARAMETERS; + + Session *session = TEE_Malloc(sizeof (Session), 0); + if (!session) + return TEE_ERROR_OUT_OF_MEMORY; + + char *pin = params[0].memref.buffer; + size_t pin_sz = params[0].memref.size; + + *ctx = session; + + return so_init(pin, pin_sz, session); +} + +void TA_CloseSessionEntryPoint(void *ctx) +{ + Session *session = ctx; + if (session == NULL) + return; + + so_free(session); + TEE_Free(ctx); +} + +TEE_Result TA_InvokeCommandEntryPoint( + void *session, + uint32_t command, + uint32_t param_types, + TEE_Param params[4]) +{ + switch (command) { + case TA_BLIQ_STORAGE_CMD_CREATE_KEY: + return create_key(session, param_types, params); + case TA_BLIQ_STORAGE_CMD_CHECK_KEY: + return check_key(session, param_types, params); + case TA_BLIQ_STORAGE_CMD_DELETE_KEY: + return delete_key(param_types, params); + case TA_BLIQ_STORAGE_CMD_ENCRYPT: + return encrypt_data(session, param_types, params); + case TA_BLIQ_STORAGE_CMD_DECRYPT: + return decrypt_data(session, param_types, params); + default: + EMSG("Command ID 0x%x is not supported", command); + return TEE_ERROR_NOT_SUPPORTED; + } +} diff --git a/bliq_storage/ta/include/bliq_storage_ta.h b/bliq_storage/ta/include/bliq_storage_ta.h new file mode 100644 index 0000000..2937e51 --- /dev/null +++ b/bliq_storage/ta/include/bliq_storage_ta.h @@ -0,0 +1,59 @@ + +#ifndef __BLIQ_STORAGE_H__ +#define __BLIQ_STORAGE_H__ + +/* UUID of the trusted application */ +#define TA_BLIQ_STORAGE_UUID \ + { 0x0651d840, 0xa91b, 0x4b3f, \ + { 0xa2, 0x22, 0xb6, 0x8c, 0xd1, 0x95, 0x23, 0x1c } } + +/* + * TA_BLIQ_STORAGE_CMD_CREATE_KEY - Create RSA key and store it + * in encrypted form (AES pin) inside secure storage file + * param[0] (memref) ID used the identify RSA key + * param[1] unused + * param[2] unused + * param[3] unused + */ +#define TA_BLIQ_STORAGE_CMD_CREATE_KEY 1 + +/* + * TA_BLIQ_STORAGE_CMD_CHECK_KEY - Check if tagget RSA key pair + * exists and is accessinbel + * param[0] (memref) ID used the identify RSA key + * param[1] unused + * param[2] unused + * param[3] unused + */ +#define TA_BLIQ_STORAGE_CMD_CHECK_KEY 2 + +/* + * TA_BLIQ_STORAGE_CMD_DELETE - Delete tagget RSA key pair + * param[0] (memref) ID used the identify the persistent object + * param[1] unused + * param[2] unused + * param[3] unused + */ +#define TA_BLIQ_STORAGE_CMD_DELETE_KEY 3 + +/* + * TA_BLIQ_STORAGE_CMD_ENCRYPT - Encrypt arbitrary string + * with protected RSA KeyPair from secure storage + * param[0] (memref) ID used the identify RSA key + * param[1] (memref) plain data to encrypt + * param[2] (memref) encrypted data + * param[3] unused + */ +#define TA_BLIQ_STORAGE_CMD_ENCRYPT 4 + +/* + * TA_BLIQ_STORAGE_CMD_DECRYPT - Decrypt previosly encrypted string + * with protected RSA KeyPair from secure storage + * param[0] (memref) ID used the identify RSA key + * param[1] (memref) encrypted data + * param[2] (memref) decrypted data + * param[3] unused + */ +#define TA_BLIQ_STORAGE_CMD_DECRYPT 5 + +#endif /* __BLIQ_STORAGE_H__ */ diff --git a/bliq_storage/ta/key_pair.c b/bliq_storage/ta/key_pair.c new file mode 100644 index 0000000..c5afe58 --- /dev/null +++ b/bliq_storage/ta/key_pair.c @@ -0,0 +1,263 @@ +#include +#include "operations.h" +#include "key_pair.h" + +static char* storeNext( + TEE_ObjectHandle kp, + uint32_t attribute_id, + char *curr, const char * const end) +{ + TEE_Result res; + uint32_t attribute_sz; + + if (curr == NULL) + return NULL; + + TEE_GetObjectBufferAttribute(kp, attribute_id, NULL, &attribute_sz); + if (curr + sizeof(uint32_t) + attribute_sz > end) + return NULL; + + EMSG("[INFO] -->> attr_size %u\n", attribute_sz); + + // store attribute size + curr[0] = attribute_sz & 0xFF; + curr[1] = attribute_sz >> 8 & 0xFF; + curr[2] = attribute_sz >> 16 & 0xFF; + curr[3] = attribute_sz >> 24 & 0xFF; + + curr += sizeof(uint32_t); // move pointer + + res = TEE_GetObjectBufferAttribute(kp, attribute_id, curr, &attribute_sz); + if (res != TEE_SUCCESS) + return NULL; + + return curr + attribute_sz; +} + +static char* readNext( + TEE_Attribute *key_attr, + uint32_t attribute_id, + char *curr, const char * const end) +{ + if (curr > end || curr == NULL) + return NULL; + + uint32_t attribute_sz = curr[3] <<24 | curr[2] <<16 | curr[1] <<8 | curr[0]; + EMSG("[INFO] <<-- attr_size %u\n", attribute_sz); + curr += sizeof(uint32_t); // move pointer + + TEE_InitRefAttribute(key_attr, attribute_id, curr, attribute_sz); + + return curr + attribute_sz; +} + +TEE_Result kp_create( + TEE_ObjectHandle *kp) +{ + const uint32_t key_type = TEE_TYPE_RSA_KEYPAIR; + const uint32_t key_size = 1024; // fast calculations + + TEE_Result res; + TEE_ObjectHandle key = NULL; + + res = TEE_AllocateTransientObject( + key_type, key_size, + &key); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_create: TEE_AllocateTransientObject(%#" PRIx32 ", %" PRId32 "): %#" PRIx32, key_type, key_size, res); + goto exit; + } + + res = TEE_GenerateKey( + key, key_size, + NULL, 0); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_create: TEE_GenerateKey(%" PRId32 "): %#" PRIx32, key_size, res); + goto exit; + } + + *kp = key; + key = NULL; + +exit: + if (key) + TEE_FreeTransientObject(key); + + return res; +} + +TEE_Result kp_serialize( + TEE_ObjectHandle kp, + char *serilized, uint32_t *serilized_sz) +{ + char *curr = serilized; + char *end = serilized + *serilized_sz; + + curr = storeNext(kp, TEE_ATTR_RSA_MODULUS , curr, end); + curr = storeNext(kp, TEE_ATTR_RSA_PUBLIC_EXPONENT , curr, end); + curr = storeNext(kp, TEE_ATTR_RSA_PRIVATE_EXPONENT, curr, end); + curr = storeNext(kp, TEE_ATTR_RSA_PRIME1 , curr, end); + curr = storeNext(kp, TEE_ATTR_RSA_PRIME2 , curr, end); + curr = storeNext(kp, TEE_ATTR_RSA_EXPONENT1 , curr, end); + curr = storeNext(kp, TEE_ATTR_RSA_EXPONENT2 , curr, end); + curr = storeNext(kp, TEE_ATTR_RSA_COEFFICIENT , curr, end); + + if (curr == NULL) + return TEE_ERROR_OVERFLOW; + + *serilized_sz = curr - serilized; + + return TEE_SUCCESS; +} + +TEE_Result kp_deserialize( + char *serilized, uint32_t serilized_sz, + TEE_ObjectHandle *kp) +{ + TEE_Result res; + TEE_Attribute key_attr[8]; + uint32_t key_attr_count = 8; + + TEE_ObjectHandle transient_kp = NULL; + const uint32_t key_type = TEE_TYPE_RSA_KEYPAIR; + const uint32_t key_size = 1024; // fast calculations + + char *curr = serilized; + char *curr_end = serilized + serilized_sz; + + curr = readNext(&key_attr[0], TEE_ATTR_RSA_MODULUS , curr, curr_end); + curr = readNext(&key_attr[1], TEE_ATTR_RSA_PUBLIC_EXPONENT , curr, curr_end); + curr = readNext(&key_attr[2], TEE_ATTR_RSA_PRIVATE_EXPONENT, curr, curr_end); + curr = readNext(&key_attr[3], TEE_ATTR_RSA_PRIME1 , curr, curr_end); + curr = readNext(&key_attr[4], TEE_ATTR_RSA_PRIME2 , curr, curr_end); + curr = readNext(&key_attr[5], TEE_ATTR_RSA_EXPONENT1 , curr, curr_end); + curr = readNext(&key_attr[6], TEE_ATTR_RSA_EXPONENT2 , curr, curr_end); + curr = readNext(&key_attr[7], TEE_ATTR_RSA_COEFFICIENT , curr, curr_end); + + if (curr == NULL) { + res = TEE_ERROR_OVERFLOW; + goto exit; + } + + res = TEE_AllocateTransientObject( + key_type, key_size, + &transient_kp); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_deserialize(): TEE_AllocateTransientObject(%#" PRIx32 ", %" PRId32 "): %#" PRIx32, key_type, key_size, res); + goto exit; + } + + res = TEE_PopulateTransientObject( + transient_kp, + key_attr, key_attr_count); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: kp_deserialize(): TEE_PopulateTransientObject: 0x%x", res); + goto exit; + } + + *kp = transient_kp; + transient_kp = NULL; + +exit: + if (transient_kp) + TEE_FreeTransientObject(transient_kp); + return res; +} + +TEE_Result kp_encrypt( + TEE_ObjectHandle kp, + void *inbuf, uint32_t inbuf_sz, + void *outbuf, uint32_t *outbuf_sz) +{ + const uint32_t alg = TEE_ALG_RSAES_PKCS1_V1_5; + + TEE_Result res; + TEE_OperationHandle op = NULL; + TEE_ObjectInfo key_info; + + res = TEE_GetObjectInfo1(kp, &key_info); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_GetObjectInfo1: %#" PRIx32, res); + goto exit; + } + + res = TEE_AllocateOperation( + &op, + alg, TEE_MODE_ENCRYPT, + key_info.keySize); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_AllocateOperation(TEE_MODE_ENCRYPT, %#" PRIx32 ", %" PRId32 "): %#" PRIx32, alg, key_info.keySize, res); + goto exit; + } + + res = TEE_SetOperationKey(op, kp); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_SetOperationKey: %#" PRIx32, res); + goto exit; + } + + res = TEE_AsymmetricEncrypt( + op, + NULL, 0, + inbuf, inbuf_sz, + outbuf, outbuf_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_AsymmetricEncrypt(%u, %u): 0x%x", inbuf_sz, *outbuf_sz, res); + goto exit; + } + +exit: + if (op) + TEE_FreeOperation(op); + + return res; +} + +TEE_Result kp_decrypt( + TEE_ObjectHandle kp, + void *inbuf, uint32_t inbuf_sz, + void *outbuf, uint32_t *outbuf_sz) +{ + const uint32_t alg = TEE_ALG_RSAES_PKCS1_V1_5; + + TEE_Result res; + TEE_OperationHandle op = NULL; + TEE_ObjectInfo key_info; + + res = TEE_GetObjectInfo1(kp, &key_info); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_GetObjectInfo1: %#" PRIx32, res); + goto exit; + } + + res = TEE_AllocateOperation( + &op, + alg, TEE_MODE_DECRYPT, + key_info.keySize); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_AllocateOperation(TEE_MODE_DECRYPT, %#" PRIx32 ", %" PRId32 "): %#" PRIx32, alg, key_info.keySize, res); + goto exit; + } + + res = TEE_SetOperationKey(op, kp); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_SetOperationKey: %#" PRIx32, res); + goto exit; + } + + res = TEE_AsymmetricDecrypt( + op, + NULL, 0, + inbuf, inbuf_sz, + outbuf, outbuf_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR] kp_encrypt: TEE_AsymmetricEncrypt(%u, %u): 0x%x", inbuf_sz, *outbuf_sz, res); + goto exit; + } + +exit: + if (op) + TEE_FreeOperation(op); + + return res; +} diff --git a/bliq_storage/ta/key_pair.h b/bliq_storage/ta/key_pair.h new file mode 100644 index 0000000..105925b --- /dev/null +++ b/bliq_storage/ta/key_pair.h @@ -0,0 +1,27 @@ +#include + +#ifndef KEY_PAIR_H +#define KEY_PAIR_H + +TEE_Result kp_create( + TEE_ObjectHandle *kp); + +TEE_Result kp_serialize( + TEE_ObjectHandle kp, + char *serilized, uint32_t *serilized_sz); + +TEE_Result kp_deserialize( + char *serilized, uint32_t serilized_sz, + TEE_ObjectHandle *kp); + +TEE_Result kp_encrypt( + TEE_ObjectHandle kp, + void *in, uint32_t in_sz, + void *out, uint32_t *out_sz); + +TEE_Result kp_decrypt( + TEE_ObjectHandle kp, + void *in, uint32_t in_sz, + void *out, uint32_t *out_sz); + +#endif /*KEY_PAIR_H*/ \ No newline at end of file diff --git a/bliq_storage/ta/operations.c b/bliq_storage/ta/operations.c new file mode 100644 index 0000000..ca0fe49 --- /dev/null +++ b/bliq_storage/ta/operations.c @@ -0,0 +1,151 @@ +#include +#include "operations.h" + +char iv[] = { + 0x7D, 0x3F, 0x80, 0x6C, 0x35, 0x7E, 0x04, 0xC2, + 0x92, 0x4C, 0x67, 0x30, 0xBA, 0xFA, 0xE0, 0xF7}; +uint32_t iv_sz = sizeof(iv); + + +static TEE_Result sha256( + char *in, size_t in_sz, + char *out, uint32_t *out_sz) +{ + TEE_Result res; + TEE_OperationHandle hDigest = NULL; + + res = TEE_AllocateOperation( + &hDigest, + TEE_ALG_SHA256, TEE_MODE_DIGEST, + 0); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: TEE_AllocateOperation: 0x%x", res); + goto exit; + } + + res = TEE_DigestDoFinal( + hDigest, + in, in_sz, + out, out_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: TEE_DigestDoFinal: 0x%x", res); + goto exit; + } + +exit: + if (hDigest) + TEE_FreeOperation(hDigest); + + return res; +} + +/* + * Session Operations + */ +TEE_Result so_init( + char *pin, size_t pin_sz, + Session *session) +{ + TEE_Result res; + TEE_ObjectHandle hSessionKey = NULL; + TEE_Attribute key_attr = { 0 }; + uint32_t key_attr_count = 1; + + char key[32]; // 256bit + uint32_t key_sz = sizeof(key); + + res = sha256( + pin, pin_sz, + key, &key_sz); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: sha256: %d", res); + goto exit; + } + + res = TEE_AllocateTransientObject( + TEE_TYPE_AES, 256, + &hSessionKey); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: SessionKey TEE_AllocateTransientObject: 0x%x", res); + goto exit; + } + + TEE_InitRefAttribute(&key_attr, TEE_ATTR_SECRET_VALUE, key, key_sz); + res = TEE_PopulateTransientObject( + hSessionKey, + &key_attr, key_attr_count); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: SessionKey TEE_PopulateTransientObject: 0x%x", res); + goto exit; + } + + res = TEE_AllocateOperation( + &session->hSK_encrypt, + TEE_ALG_AES_CTR, TEE_MODE_ENCRYPT, 256); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: SessionKey hSK_encrypt: TEE_AllocateOperation: 0x%x", res); + goto exit; + } + + res = TEE_SetOperationKey( + session->hSK_encrypt, + hSessionKey); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: SessionKey TEE_SetOperationKey(sk_encrypt): 0x%x", res); + goto exit; + } + + res = TEE_AllocateOperation( + &session->hSK_decrypt, + TEE_ALG_AES_CTR, TEE_MODE_DECRYPT, 256); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: SessionKey hSK_decrypt: TEE_AllocateOperation: 0x%x", res); + goto exit; + } + + res = TEE_SetOperationKey( + session->hSK_decrypt, + hSessionKey); + if (res != TEE_SUCCESS) { + EMSG("[ERR]: SessionKey TEE_SetOperationKey(sk_decrypt): 0x%x", res); + goto exit; + } + +exit: + if (hSessionKey) + TEE_FreeTransientObject(hSessionKey); + + return res; +} + +void so_free( + Session *session) +{ + TEE_FreeOperation(session->hSK_encrypt); + TEE_FreeOperation(session->hSK_decrypt); +} + + +TEE_Result so_encrypt( + Session *session, + void *in, uint32_t in_sz, + void *out, uint32_t *out_sz) +{ + TEE_CipherInit(session->hSK_encrypt, iv, iv_sz); + + return TEE_CipherDoFinal(session->hSK_encrypt, + in, in_sz, // src + out, out_sz); // dest +} + +TEE_Result so_decrypt( + Session *session, + void *in, uint32_t in_sz, + void *out, uint32_t *out_sz) +{ + TEE_CipherInit(session->hSK_decrypt, iv, iv_sz); + + return TEE_CipherDoFinal(session->hSK_decrypt, + in, in_sz, // src + out, out_sz); // dest +} \ No newline at end of file diff --git a/bliq_storage/ta/operations.h b/bliq_storage/ta/operations.h new file mode 100644 index 0000000..c7b6aab --- /dev/null +++ b/bliq_storage/ta/operations.h @@ -0,0 +1,28 @@ +#include + +#ifndef OPERATIONS_H +#define OPERATIONS_H + +typedef struct { + TEE_OperationHandle hSK_encrypt; + TEE_OperationHandle hSK_decrypt; +} Session; + +TEE_Result so_init( + char *pin, size_t pin_sz, + Session *session); + +void so_free( + Session *session); + +TEE_Result so_encrypt( + Session *session, + void *inbuf, uint32_t inbuf_sz, + void *outbuf, uint32_t *outbuf_sz); + +TEE_Result so_decrypt( + Session *session, + void *inbuf, uint32_t inbuf_sz, + void *outbuf, uint32_t *outbuf_sz); + +#endif /*OPERATIONS_H*/ \ No newline at end of file diff --git a/bliq_storage/ta/sub.mk b/bliq_storage/ta/sub.mk new file mode 100644 index 0000000..c709bbe --- /dev/null +++ b/bliq_storage/ta/sub.mk @@ -0,0 +1,2 @@ +global-incdirs-y += include +srcs-y += bliq_storage_ta.c operations.c key_pair.c diff --git a/bliq_storage/ta/user_ta_header_defines.h b/bliq_storage/ta/user_ta_header_defines.h new file mode 100644 index 0000000..8505cf8 --- /dev/null +++ b/bliq_storage/ta/user_ta_header_defines.h @@ -0,0 +1,21 @@ +/* + * The name of this file must not be modified + */ + +#ifndef USER_TA_HEADER_DEFINES_H +#define USER_TA_HEADER_DEFINES_H + +#include + +#define TA_UUID TA_BLIQ_STORAGE_UUID + +#define TA_FLAGS (TA_FLAG_EXEC_DDR | TA_FLAG_SINGLE_INSTANCE) +#define TA_STACK_SIZE (2 * 1024) +#define TA_DATA_SIZE (32 * 1024) + +#define TA_CURRENT_TA_EXT_PROPERTIES \ + { "gp.ta.description", USER_TA_PROP_TYPE_STRING, \ + "A simple secure storage TA for BliQ" }, \ + { "gp.ta.version", USER_TA_PROP_TYPE_U32, &(const uint32_t){ 0x0010 } } + +#endif /*USER_TA_HEADER_DEFINES_H*/ diff --git a/build-docker.sh b/build-docker.sh new file mode 100755 index 0000000..65a7d76 --- /dev/null +++ b/build-docker.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euxo pipefail + +docker build -t op-tee-quemu:latest . \ No newline at end of file diff --git a/run-docker.sh b/run-docker.sh new file mode 100755 index 0000000..1080eeb --- /dev/null +++ b/run-docker.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euxo pipefail + +docker run \ + --name op-tee-secstore \ + --rm \ + -v $(pwd)/bliq_storage:/optee/optee_examples/bliq_storage \ + -e DISPLAY=docker.for.mac.host.internal:0 \ + -it op-tee-quemu:latest \ No newline at end of file diff --git a/spec/GPD_TEE_Internal_Core_API_Specification_v1.3_PublicRelease.pdf b/spec/GPD_TEE_Internal_Core_API_Specification_v1.3_PublicRelease.pdf new file mode 100644 index 0000000..bd21627 Binary files /dev/null and b/spec/GPD_TEE_Internal_Core_API_Specification_v1.3_PublicRelease.pdf differ diff --git a/spec/TEE_Client_API_Specification-V1.0.pdf b/spec/TEE_Client_API_Specification-V1.0.pdf new file mode 100644 index 0000000..f3ecf67 Binary files /dev/null and b/spec/TEE_Client_API_Specification-V1.0.pdf differ