From f86ab8e7e0de869dfa25ca05a37ee070d7e5b86b Mon Sep 17 00:00:00 2001 From: Sumit Garg Date: Wed, 6 May 2020 12:45:38 +0530 Subject: ta: add early TA to seal and unseal Linux trusted keys This patch adds an early TA which acts as Linux TEE bus device to provide a service of sealing/unsealing of trusted keys in case platform doesn't posses a TPM device or like. To do sealing/unsealing we use system pseudo TA service to derive a hardware unquie key to perform authenticated encryption/decryption (using TEE_ALG_AES_GCM algo). Also, this early TA only accepts login with a new private login method specifically used by REE kernel (TEE_LOGIN_REE_KERNEL). Signed-off-by: Sumit Garg Reviewed-by: Jens Wiklander Reviewed-by: Etienne Carriere Reviewed-by: Jerome Forissier --- ta/trusted_keys/entry.c | 330 +++++++++++++++++++++++++++++++ ta/trusted_keys/include/trusted_keys.h | 35 ++++ ta/trusted_keys/sub.mk | 3 + ta/trusted_keys/user_ta.mk | 1 + ta/trusted_keys/user_ta_header_defines.h | 20 ++ 5 files changed, 389 insertions(+) create mode 100644 ta/trusted_keys/entry.c create mode 100644 ta/trusted_keys/include/trusted_keys.h create mode 100644 ta/trusted_keys/sub.mk create mode 100644 ta/trusted_keys/user_ta.mk create mode 100644 ta/trusted_keys/user_ta_header_defines.h diff --git a/ta/trusted_keys/entry.c b/ta/trusted_keys/entry.c new file mode 100644 index 00000000..c6593ffe --- /dev/null +++ b/ta/trusted_keys/entry.c @@ -0,0 +1,330 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2019-2020, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define IV_SIZE 16 +#define TAG_SIZE 16 +#define MAX_BUF_SIZE 512 + +/* + * Acronym: + * + * TK - Trusted Key + */ + +struct tk_blob_hdr { + uint8_t reserved; + uint8_t iv[IV_SIZE]; + uint8_t tag[TAG_SIZE]; + uint8_t enc_key[]; +}; + +static TEE_Result get_random(uint32_t types, TEE_Param params[TEE_NUM_PARAMS]) +{ + DMSG("Invoked TA_CMD_GET_RANDOM"); + + if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE)) + return TEE_ERROR_BAD_PARAMETERS; + + if (!params[0].memref.buffer || !params[0].memref.size) + return TEE_ERROR_BAD_PARAMETERS; + + TEE_GenerateRandom(params[0].memref.buffer, params[0].memref.size); + + return TEE_SUCCESS; +} + +static TEE_Result derive_unique_key(uint8_t *key, uint16_t key_size, + uint8_t *extra, uint16_t extra_size) +{ + TEE_TASessionHandle sess = TEE_HANDLE_NULL; + TEE_Param params[TEE_NUM_PARAMS] = { }; + TEE_Result res = TEE_ERROR_GENERIC; + uint32_t ret_orig = 0; + uint32_t param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE); + + res = TEE_OpenTASession(&(const TEE_UUID)PTA_SYSTEM_UUID, + TEE_TIMEOUT_INFINITE, 0, NULL, &sess, + &ret_orig); + if (res) + return res; + + if (extra && extra_size) { + params[0].memref.buffer = extra; + params[0].memref.size = extra_size; + } + + params[1].memref.buffer = key; + params[1].memref.size = key_size; + + res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE, + PTA_SYSTEM_DERIVE_TA_UNIQUE_KEY, + param_types, params, &ret_orig); + + TEE_CloseTASession(sess); + + return res; +} + +static TEE_Result huk_ae_encrypt(TEE_OperationHandle crypto_op, uint8_t *in, + uint32_t in_sz, uint8_t *out, uint32_t *out_sz) +{ + TEE_Result res = TEE_ERROR_GENERIC; + struct tk_blob_hdr *hdr = (struct tk_blob_hdr *)out; + uint32_t enc_key_len = in_sz; + uint32_t tag_len = TAG_SIZE; + + hdr->reserved = 0; + TEE_GenerateRandom(hdr->iv, IV_SIZE); + + res = TEE_AEInit(crypto_op, hdr->iv, IV_SIZE, TAG_SIZE * 8, 0, 0); + if (res) + return res; + + res = TEE_AEEncryptFinal(crypto_op, in, in_sz, hdr->enc_key, + &enc_key_len, hdr->tag, &tag_len); + if (res || tag_len != TAG_SIZE) + return TEE_ERROR_SECURITY; + + if (ADD_OVERFLOW(enc_key_len, sizeof(*hdr), out_sz)) + return TEE_ERROR_SECURITY; + + return res; +} + +static TEE_Result huk_ae_decrypt(TEE_OperationHandle crypto_op, uint8_t *in, + uint32_t in_sz, uint8_t *out, uint32_t *out_sz) +{ + TEE_Result res = TEE_ERROR_GENERIC; + struct tk_blob_hdr *hdr = (struct tk_blob_hdr *)in; + uint32_t enc_key_len = 0; + + if (SUB_OVERFLOW(in_sz, sizeof(*hdr), &enc_key_len)) + return TEE_ERROR_SECURITY; + + res = TEE_AEInit(crypto_op, hdr->iv, IV_SIZE, TAG_SIZE * 8, 0, 0); + if (res) + return res; + + res = TEE_AEDecryptFinal(crypto_op, hdr->enc_key, enc_key_len, out, + out_sz, hdr->tag, TAG_SIZE); + if (res) + res = TEE_ERROR_SECURITY; + + return res; +} + +static TEE_Result huk_crypt(TEE_OperationMode mode, uint8_t *in, uint32_t in_sz, + uint8_t *out, uint32_t *out_sz) +{ + TEE_Result res = TEE_ERROR_GENERIC; + TEE_OperationHandle crypto_op = TEE_HANDLE_NULL; + TEE_ObjectHandle hkey = TEE_HANDLE_NULL; + uint8_t huk_key[TA_DERIVED_KEY_MAX_SIZE] = { }; + TEE_Attribute attr = { }; + + res = TEE_AllocateOperation(&crypto_op, TEE_ALG_AES_GCM, mode, + sizeof(huk_key) * 8); + if (res) + return res; + + res = derive_unique_key(huk_key, sizeof(huk_key), NULL, 0); + if (res) { + EMSG("derive_unique_key failed: returned %#"PRIx32, res); + goto out_op; + } + + res = TEE_AllocateTransientObject(TEE_TYPE_AES, sizeof(huk_key) * 8, + &hkey); + if (res) + goto out_op; + + attr.attributeID = TEE_ATTR_SECRET_VALUE; + attr.content.ref.buffer = huk_key; + attr.content.ref.length = sizeof(huk_key); + + res = TEE_PopulateTransientObject(hkey, &attr, 1); + if (res) + goto out_key; + + res = TEE_SetOperationKey(crypto_op, hkey); + if (res) + goto out_key; + + if (mode == TEE_MODE_ENCRYPT) { + res = huk_ae_encrypt(crypto_op, in, in_sz, out, out_sz); + if (res) + EMSG("huk_AE_encrypt failed: returned %#"PRIx32, res); + } else if (mode == TEE_MODE_DECRYPT) { + res = huk_ae_decrypt(crypto_op, in, in_sz, out, out_sz); + if (res) + EMSG("huk_AE_decrypt failed: returned %#"PRIx32, res); + } else { + TEE_Panic(0); + } + +out_key: + TEE_FreeTransientObject(hkey); +out_op: + TEE_FreeOperation(crypto_op); + memzero_explicit(huk_key, sizeof(huk_key)); + return res; +} + +static TEE_Result seal_trusted_key(uint32_t types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res = TEE_SUCCESS; + uint8_t *in = NULL; + uint32_t in_sz = 0; + uint8_t *out = NULL; + uint32_t out_sz = 0; + + DMSG("Invoked TA_CMD_SEAL"); + + if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE)) + return TEE_ERROR_BAD_PARAMETERS; + + in = params[0].memref.buffer; + in_sz = params[0].memref.size; + out = params[1].memref.buffer; + out_sz = params[1].memref.size; + + if (!in || !in_sz || in_sz > MAX_BUF_SIZE) + return TEE_ERROR_BAD_PARAMETERS; + if ((!out && out_sz) || + (out && !ALIGNMENT_IS_OK(out, struct tk_blob_hdr)) || + out_sz > MAX_BUF_SIZE) + return TEE_ERROR_BAD_PARAMETERS; + + if ((in_sz + sizeof(struct tk_blob_hdr)) > out_sz) { + params[1].memref.size = in_sz + sizeof(struct tk_blob_hdr); + return TEE_ERROR_SHORT_BUFFER; + } + + res = huk_crypt(TEE_MODE_ENCRYPT, in, in_sz, out, &out_sz); + if (res == TEE_SUCCESS) { + assert(out_sz == in_sz + sizeof(struct tk_blob_hdr)); + params[1].memref.size = out_sz; + } + + return res; +} + +static TEE_Result unseal_trusted_key(uint32_t types, + TEE_Param params[TEE_NUM_PARAMS]) +{ + TEE_Result res = TEE_SUCCESS; + uint8_t *in = NULL; + uint32_t in_sz = 0; + uint8_t *out = NULL; + uint32_t out_sz = 0; + + DMSG("Invoked TA_CMD_UNSEAL"); + + if (types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_NONE)) + return TEE_ERROR_BAD_PARAMETERS; + + in = params[0].memref.buffer; + in_sz = params[0].memref.size; + out = params[1].memref.buffer; + out_sz = params[1].memref.size; + + if (!in || !ALIGNMENT_IS_OK(in, struct tk_blob_hdr) || + in_sz <= sizeof(struct tk_blob_hdr) || in_sz > MAX_BUF_SIZE) + return TEE_ERROR_BAD_PARAMETERS; + if ((!out && out_sz) || out_sz > MAX_BUF_SIZE) + return TEE_ERROR_BAD_PARAMETERS; + + if (in_sz > (out_sz + sizeof(struct tk_blob_hdr))) { + params[1].memref.size = in_sz - sizeof(struct tk_blob_hdr); + return TEE_ERROR_SHORT_BUFFER; + } + + res = huk_crypt(TEE_MODE_DECRYPT, in, in_sz, out, &out_sz); + if (res == TEE_SUCCESS) { + assert(out_sz == in_sz - sizeof(struct tk_blob_hdr)); + params[1].memref.size = out_sz; + } + + return res; +} + +TEE_Result TA_CreateEntryPoint(void) +{ + return TEE_SUCCESS; +} + +void TA_DestroyEntryPoint(void) +{ +} + +TEE_Result TA_OpenSessionEntryPoint(uint32_t pt __unused, + TEE_Param params[TEE_NUM_PARAMS] __unused, + void **session __unused) +{ + TEE_Result res = TEE_ERROR_GENERIC; + TEE_PropSetHandle h = TEE_HANDLE_NULL; + TEE_Identity id = { }; + + res = TEE_AllocatePropertyEnumerator(&h); + if (res) + goto out; + + TEE_StartPropertyEnumerator(h, TEE_PROPSET_CURRENT_CLIENT); + + res = TEE_GetPropertyAsIdentity(h, NULL, &id); + if (res) + goto out; + + if (id.login != TEE_LOGIN_REE_KERNEL) + res = TEE_ERROR_ACCESS_DENIED; + +out: + if (h) + TEE_FreePropertyEnumerator(h); + return res; +} + +void TA_CloseSessionEntryPoint(void *sess __unused) +{ +} + +TEE_Result TA_InvokeCommandEntryPoint(void *sess __unused, uint32_t cmd, + uint32_t pt, + TEE_Param params[TEE_NUM_PARAMS]) +{ + switch (cmd) { + case TA_CMD_GET_RANDOM: + return get_random(pt, params); + case TA_CMD_SEAL: + return seal_trusted_key(pt, params); + case TA_CMD_UNSEAL: + return unseal_trusted_key(pt, params); + default: + EMSG("Command ID %#"PRIx32" is not supported", cmd); + return TEE_ERROR_NOT_SUPPORTED; + } +} diff --git a/ta/trusted_keys/include/trusted_keys.h b/ta/trusted_keys/include/trusted_keys.h new file mode 100644 index 00000000..1571b370 --- /dev/null +++ b/ta/trusted_keys/include/trusted_keys.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (C) 2019-2020, Linaro Limited + */ + +#ifndef TRUSTED_KEYS_H +#define TRUSTED_KEYS_H + +#define TRUSTED_KEYS_UUID { 0xf04a0fe7, 0x1f5d, 0x4b9b, \ + { 0xab, 0xf7, 0x61, 0x9b, 0x85, 0xb4, 0xce, 0x8c } } + +/* + * Get random data for symmetric key + * + * [out] memref[0] Random data + */ +#define TA_CMD_GET_RANDOM 0x0 + +/* + * Seal trusted key using hardware unique key + * + * [in] memref[0] Plain key + * [out] memref[1] Sealed key datablob + */ +#define TA_CMD_SEAL 0x1 + +/* + * Unseal trusted key using hardware unique key + * + * [in] memref[0] Sealed key datablob + * [out] memref[1] Plain key + */ +#define TA_CMD_UNSEAL 0x2 + +#endif /* TRUSTED_KEYS_H */ diff --git a/ta/trusted_keys/sub.mk b/ta/trusted_keys/sub.mk new file mode 100644 index 00000000..f1b35c03 --- /dev/null +++ b/ta/trusted_keys/sub.mk @@ -0,0 +1,3 @@ +global-incdirs-y += include +global-incdirs-y += . +srcs-y += entry.c diff --git a/ta/trusted_keys/user_ta.mk b/ta/trusted_keys/user_ta.mk new file mode 100644 index 00000000..bcb59c08 --- /dev/null +++ b/ta/trusted_keys/user_ta.mk @@ -0,0 +1 @@ +user-ta-uuid := f04a0fe7-1f5d-4b9b-abf7-619b85b4ce8c diff --git a/ta/trusted_keys/user_ta_header_defines.h b/ta/trusted_keys/user_ta_header_defines.h new file mode 100644 index 00000000..2fc6689a --- /dev/null +++ b/ta/trusted_keys/user_ta_header_defines.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright (c) 2020, Linaro Limited + */ + +#ifndef USER_TA_HEADER_DEFINES_H +#define USER_TA_HEADER_DEFINES_H + +#include + +#define TA_UUID TRUSTED_KEYS_UUID + +#define TA_FLAGS (TA_FLAG_SINGLE_INSTANCE | \ + TA_FLAG_MULTI_SESSION | \ + TA_FLAG_DEVICE_ENUM) + +#define TA_STACK_SIZE (4 * 1024) +#define TA_DATA_SIZE (16 * 1024) + +#endif /*USER_TA_HEADER_DEFINES_H*/ -- cgit v1.2.3