From: Mike Engel Date: Fri, 26 May 2023 11:21:43 +0200 Subject: [PATCH] Implement support for environment encryption using Optee Co-authored-by: Javier Viguera Signed-off-by: Mike Engel Signed-off-by: Javier Viguera --- src/CMakeLists.txt | 3 + src/crypt.c | 10 ++- src/crypt_optee.c | 172 +++++++++++++++++++++++++++++++++++++++++++++ src/crypt_optee.h | 10 +++ 4 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 src/crypt_optee.c create mode 100644 src/crypt_optee.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 638f1c1..f218b35 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,8 @@ cmake_minimum_required (VERSION 2.6) SET(libubootenv_SOURCES crypt.c crypt.h + crypt_optee.c + crypt_optee.h md5.c md5.h uboot_env.c @@ -26,6 +28,7 @@ ADD_LIBRARY(ubootenv_static STATIC ${libubootenv_SOURCES} ${include_HEADERS}) SET_TARGET_PROPERTIES(ubootenv_static PROPERTIES OUTPUT_NAME ubootenv) add_executable(fw_printenv fw_printenv.c) target_link_libraries(ubootenv z yaml) +target_link_libraries(ubootenv teec) target_link_libraries(fw_printenv ubootenv) add_custom_target(fw_setenv ALL ${CMAKE_COMMAND} -E create_symlink fw_printenv fw_setenv) diff --git a/src/crypt.c b/src/crypt.c index 213cffd..e3f9a5d 100644 --- a/src/crypt.c +++ b/src/crypt.c @@ -15,6 +15,7 @@ #include #include "caam_keyblob.h" +#include "crypt_optee.h" #include "md5.h" /* @@ -168,7 +169,14 @@ free: int env_crypt(char *data, unsigned int size, const int enc) { - return env_caam_crypt(data, size, enc); + if (is_env_optee_encrypted()) { + unsigned char key_modifier[16]; + if (env_get_keymod(key_modifier)) + return -1; + return env_optee_crypt((char *)key_modifier, data, size, enc); + } else { + return env_caam_crypt(data, size, enc); + } } int is_env_encrypted(void) diff --git a/src/crypt_optee.c b/src/crypt_optee.c new file mode 100644 index 0000000..fc74141 --- /dev/null +++ b/src/crypt_optee.c @@ -0,0 +1,172 @@ +/* + * Copyright 2024 Digi International Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +#define AES_BLOCK_LENGTH 16 + +/* From TA's public header (aes_ta.h) */ +#define TA_AES_UUID \ + { 0xc2fad363, 0x5d9f, 0x4fc4, \ + { 0xa4, 0x17, 0x55, 0x58, 0x41, 0xe0, 0x57, 0x45 } } +#define TA_AES_ALGO_ECB 0 +#define TA_AES_ALGO_CBC 1 +#define TA_AES_ALGO_CTR 2 +#define TA_AES_SIZE_128BIT (128 / 8) +#define TA_AES_SIZE_256BIT (256 / 8) +#define TA_AES_MODE_DECODE 0 +#define TA_AES_MODE_ENCODE 1 +#define TA_AES_CMD_PREPARE 0 +#define TA_AES_CMD_SET_KEY 1 +#define TA_AES_CMD_SET_IV 2 +#define TA_AES_CMD_CIPHER 3 + +struct tee_ctx { + TEEC_Context ctx; + TEEC_Session sess; +}; + +static void prepare_tee_session(struct tee_ctx *ctx) +{ + TEEC_Result ret; + uint32_t origin; + TEEC_UUID uuid = TA_AES_UUID; + + ret = TEEC_InitializeContext(NULL, &ctx->ctx); + if (ret != TEEC_SUCCESS) + printf("TEEC_InitializeContext failed with code 0x%x", ret); + + /* Open a session with the TA */ + ret = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid, + TEEC_LOGIN_PUBLIC, NULL, NULL, &origin); + if (ret != TEEC_SUCCESS) + printf("TEEC_Opensession failed with code 0x%x origin 0x%x", + ret, origin); + +} + +static void terminate_tee_session(struct tee_ctx *ctx) +{ + TEEC_CloseSession(&ctx->sess); + TEEC_FinalizeContext(&ctx->ctx); +} + +static void prepare_aes(struct tee_ctx *ctx, int encode) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, + TEEC_VALUE_INPUT, + TEEC_VALUE_INPUT, TEEC_NONE); + + op.params[0].value.a = TA_AES_ALGO_CTR; + op.params[1].value.a = TA_AES_SIZE_256BIT; + op.params[2].value.a = encode ? TA_AES_MODE_ENCODE : TA_AES_MODE_DECODE; + + res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_PREPARE, &op, &origin); + if (res != TEEC_SUCCESS) + printf("TEEC_InvokeCommand(PREPARE) failed 0x%x origin 0x%x", + res, origin); +} + +static void set_key(struct tee_ctx *ctx, size_t key_sz) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + + memset(&op, 0, sizeof(op)); + + op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, + TEEC_NONE, TEEC_NONE, TEEC_NONE); + + op.params[0].value.a = key_sz; + + res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_KEY, &op, &origin); + if (res != TEEC_SUCCESS) + printf("TEEC_InvokeCommand(SET_KEY) failed 0x%x origin 0x%x", + res, origin); +} + +static void set_iv(struct tee_ctx *ctx, char *iv, size_t iv_sz) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + + 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 = iv; + op.params[0].tmpref.size = iv_sz; + + res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_IV, &op, &origin); + if (res != TEEC_SUCCESS) + printf("TEEC_InvokeCommand(SET_IV) failed 0x%x origin 0x%x", + res, origin); +} + +static void cipher_buffer(struct tee_ctx *ctx, char *in, char *out, size_t sz) +{ + TEEC_Operation op; + uint32_t origin; + TEEC_Result res; + + memset(&op, 0, sizeof(op)); + op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT, + TEEC_MEMREF_TEMP_OUTPUT, + TEEC_NONE, TEEC_NONE); + op.params[0].tmpref.buffer = in; + op.params[0].tmpref.size = sz; + op.params[1].tmpref.buffer = out; + op.params[1].tmpref.size = sz; + + res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_CIPHER, &op, &origin); + if (res != TEEC_SUCCESS) + printf("TEEC_InvokeCommand(CIPHER) failed 0x%x origin 0x%x", + res, origin); +} + +int env_optee_crypt(char *keymod, char *data, unsigned int size, const int enc) +{ + struct tee_ctx tee; + char *cryptdata; + int ret = 0; + + prepare_tee_session(&tee); + prepare_aes(&tee, enc); + set_key(&tee, TA_AES_SIZE_256BIT); + set_iv(&tee, keymod, AES_BLOCK_LENGTH); + cryptdata = calloc(1, size); + if (cryptdata) { + cipher_buffer(&tee, data, cryptdata, size); + memcpy(data, cryptdata, size); + free(cryptdata); + } else { + printf("%s: can't allocate memory\n", __func__); + ret = -ENOMEM; + } + terminate_tee_session(&tee); + + return ret; +} + +int is_env_optee_encrypted(void) +{ + const char *dt_prop = + "/proc/device-tree/digi,uboot-env,encrypted-optee"; + + return access(dt_prop, F_OK) != -1; +} diff --git a/src/crypt_optee.h b/src/crypt_optee.h new file mode 100644 index 0000000..e0c77a7 --- /dev/null +++ b/src/crypt_optee.h @@ -0,0 +1,10 @@ +/* + * Copyright 2024 Digi International Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#pragma once + +int env_optee_crypt(char *keymod, char *data, unsigned int size, const int enc); +int is_env_optee_encrypted(void);