Skip to content

Commit

Permalink
core: add framework to load REE-FS encrypted TAs
Browse files Browse the repository at this point in the history
Add framework to support loading of encrypted TAs from REE-FS using
symmetric authenticated encryption scheme supported by OP-TEE.

The default encryption key is derived from hardware unique key which
can be overridden via platform specific encryption key.

Signed-off-by: Sumit Garg <[email protected]>
Reviewed-by: Jens Wiklander <[email protected]>
  • Loading branch information
b49020 authored and jforissier committed Nov 22, 2019
1 parent c693a9d commit e1afc43
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 8 deletions.
26 changes: 25 additions & 1 deletion core/arch/arm/kernel/otp_stubs.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2015, Linaro Limited
* Copyright (c) 2015, 2019, Linaro Limited
*/

#include <assert.h>
#include <inttypes.h>
#include <kernel/tee_common_otp.h>
#include <kernel/huk_subkey.h>
#include <signed_hdr.h>
#include <ta_pub_key.h>

/*
* Override these in your platform code to really fetch device-unique
Expand All @@ -27,3 +30,24 @@ __weak int tee_otp_get_die_id(uint8_t *buffer, size_t len)

return 0;
}

/*
* Override this API on your platform to provide TA encryption key as
* per your security requirements. There can be two options for this key:
*
* 1) Unique per device encryption key.
* 2) Class wide encryption key.
*
* The default implementation chooses option (1).
*/
__weak TEE_Result tee_otp_get_ta_enc_key(uint32_t key_type __maybe_unused,
uint8_t *buffer, size_t len)
{
assert(key_type == SHDR_ENC_KEY_DEV_SPECIFIC);

if (huk_subkey_derive(HUK_SUBKEY_TA_ENC, ta_pub_key_modulus,
ta_pub_key_modulus_size, buffer, len))
return TEE_ERROR_SECURITY;

return TEE_SUCCESS;
}
136 changes: 129 additions & 7 deletions core/arch/arm/kernel/ree_fs_ta.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,39 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2017, Linaro Limited
* Copyright (c) 2017, 2019, Linaro Limited
*/

/*
* Security properties of REE-FS TAs
* =================================
*
* Authentication only
* -------------------
*
* Required security properties:
* 1. Authentication and non-repudiation of a TA to Service Provider (SP).
* 2. Integrity of a TA.
*
* To satisfy (1) and (2), SP needs to sign TA and OP-TEE core needs to verify
* the signature using SP public key with computed hash of the TA.
*
* Authentication along with Confidentiality
* -----------------------------------------
*
* Required security properties:
* 1. Authentication and non-repudiation of a TA to Service Provider (SP).
* 2. Confidentiality of a TA.
* 3. Integrity of an encrypted TA blob.
*
* To satisfy (1), SP needs to sign plain TA and OP-TEE core needs to verify the
* signature using SP public key with computed hash of the TA.
*
* To satisfy (2) and (3), SP needs to do authenticated encryption of TA and
* OP-TEE core needs to do authenticated decryption of TA to retrieve its
* contents. Here encryption provides the confidentiality of TA and MAC tag
* provides the integrity of encrypted TA blob.
*/

#include <assert.h>
#include <crypto/crypto.h>
#include <initcall.h>
Expand All @@ -15,6 +47,7 @@
#include <stdlib.h>
#include <string.h>
#include <tee_api_types.h>
#include <tee/tee_ta_enc_manager.h>
#include <tee/uuid.h>
#include <utee_defines.h>

Expand All @@ -25,6 +58,8 @@ struct ree_fs_ta_handle {
size_t offs;
struct shdr *shdr; /* Verified secure copy of @nw_ta's signed header */
void *hash_ctx;
void *enc_ctx;
struct shdr_encrypted_ta *ehdr;
};

/*
Expand Down Expand Up @@ -88,6 +123,7 @@ static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
size_t ta_size = 0;
TEE_Result res;
size_t offs;
struct shdr_encrypted_ta *ehdr = NULL;

handle = calloc(1, sizeof(*handle));
if (!handle)
Expand All @@ -109,7 +145,8 @@ static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
res = shdr_verify_signature(shdr);
if (res != TEE_SUCCESS)
goto error_free_payload;
if (shdr->img_type != SHDR_TA && shdr->img_type != SHDR_BOOTSTRAP_TA) {
if (shdr->img_type != SHDR_TA && shdr->img_type != SHDR_BOOTSTRAP_TA &&
shdr->img_type != SHDR_ENCRYPTED_TA) {
res = TEE_ERROR_SECURITY;
goto error_free_payload;
}
Expand All @@ -130,7 +167,8 @@ static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
goto error_free_hash;
offs = SHDR_GET_SIZE(shdr);

if (shdr->img_type == SHDR_BOOTSTRAP_TA) {
if (shdr->img_type == SHDR_BOOTSTRAP_TA ||
shdr->img_type == SHDR_ENCRYPTED_TA) {
TEE_UUID bs_uuid;
struct shdr_bootstrap_ta bs_hdr;

Expand Down Expand Up @@ -160,6 +198,38 @@ static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
offs += sizeof(bs_hdr);
}

if (shdr->img_type == SHDR_ENCRYPTED_TA) {
struct shdr_encrypted_ta img_ehdr;

if (ta_size < SHDR_GET_SIZE(shdr) +
sizeof(struct shdr_bootstrap_ta) + sizeof(img_ehdr)) {
res = TEE_ERROR_SECURITY;
goto error_free_hash;
}

memcpy(&img_ehdr, ((uint8_t *)ta + offs), sizeof(img_ehdr));

ehdr = malloc(SHDR_ENC_GET_SIZE(&img_ehdr));
if (!ehdr)
return TEE_ERROR_OUT_OF_MEMORY;

memcpy(ehdr, ((uint8_t *)ta + offs),
SHDR_ENC_GET_SIZE(&img_ehdr));

res = crypto_hash_update(hash_ctx, (uint8_t *)ehdr,
SHDR_ENC_GET_SIZE(ehdr));
if (res != TEE_SUCCESS)
goto error_free_hash;

res = tee_ta_decrypt_init(&handle->enc_ctx, ehdr,
shdr->img_size);
if (res != TEE_SUCCESS)
goto error_free_hash;

offs += SHDR_ENC_GET_SIZE(ehdr);
handle->ehdr = ehdr;
}

if (ta_size != offs + shdr->img_size) {
res = TEE_ERROR_SECURITY;
goto error_free_hash;
Expand All @@ -179,6 +249,7 @@ static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid,
error_free_payload:
thread_rpc_free_payload(mobj);
error:
free(ehdr);
shdr_free(shdr);
free(handle);
return res;
Expand Down Expand Up @@ -240,15 +311,65 @@ static TEE_Result ree_fs_ta_read(struct user_ta_store_handle *h, void *data,

if (handle->offs + len > handle->nw_ta_size)
return TEE_ERROR_BAD_PARAMETERS;
if (data) {

if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
if (data) {
dst = data; /* Hash secure buffer */
res = tee_ta_decrypt_update(handle->enc_ctx, dst, src,
len);
if (res != TEE_SUCCESS)
return TEE_ERROR_SECURITY;
} else {
size_t num_bytes = 0;
size_t b_size = MIN(1024U, len);
uint8_t *b = malloc(b_size);

if (!b)
return TEE_ERROR_OUT_OF_MEMORY;

dst = NULL;
while (num_bytes < len) {
size_t n = MIN(b_size, len - num_bytes);

res = tee_ta_decrypt_update(handle->enc_ctx, b,
src + num_bytes, n);
if (res)
break;
num_bytes += n;

res = crypto_hash_update(handle->hash_ctx, b,
n);
if (res)
break;
}

free(b);
if (res != TEE_SUCCESS)
return TEE_ERROR_SECURITY;
}
} else if (data) {
dst = data; /* Hash secure buffer (shm might be modified) */
memcpy(dst, src, len);
}
res = crypto_hash_update(handle->hash_ctx, dst, len);
if (res != TEE_SUCCESS)
return TEE_ERROR_SECURITY;

if (dst) {
res = crypto_hash_update(handle->hash_ctx, dst, len);
if (res != TEE_SUCCESS)
return TEE_ERROR_SECURITY;
}

handle->offs += len;
if (handle->offs == handle->nw_ta_size) {
if (handle->shdr->img_type == SHDR_ENCRYPTED_TA) {
/*
* Last read: time to finalize authenticated
* decryption.
*/
res = tee_ta_decrypt_final(handle->enc_ctx,
handle->ehdr, NULL, NULL, 0);
if (res != TEE_SUCCESS)
return TEE_ERROR_SECURITY;
}
/*
* Last read: time to check if our digest matches the expected
* one (from the signed header)
Expand All @@ -267,6 +388,7 @@ static void ree_fs_ta_close(struct user_ta_store_handle *h)
thread_rpc_free_payload(handle->mobj);
crypto_hash_free_ctx(handle->hash_ctx);
free(handle->shdr);
free(handle->ehdr);
free(handle);
}

Expand Down
2 changes: 2 additions & 0 deletions core/include/kernel/huk_subkey.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* @HUK_SUBKEY_SSK: Secure Storage key
* @HUK_SUBKEY_DIE_ID: Representing the die ID
* @HUK_SUBKEY_UNIQUE_TA: TA unique key
* @HUK_SUBKEY_TA_ENC: TA encryption key
*
* Add more identifiers as needed, be careful to not change the already
* assigned numbers as that will affect the derived subkey.
Expand All @@ -29,6 +30,7 @@ enum huk_subkey_usage {
HUK_SUBKEY_SSK = 1,
HUK_SUBKEY_DIE_ID = 2,
HUK_SUBKEY_UNIQUE_TA = 3,
HUK_SUBKEY_TA_ENC = 4,
};

#define HUK_SUBKEY_MAX_LEN TEE_SHA256_HASH_SIZE
Expand Down
2 changes: 2 additions & 0 deletions core/include/kernel/tee_common_otp.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ struct tee_hw_unique_key {

TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey);
int tee_otp_get_die_id(uint8_t *buffer, size_t len);
TEE_Result tee_otp_get_ta_enc_key(uint32_t key_type, uint8_t *buffer,
size_t len);

#endif /* TEE_COMMON_OTP_H */
44 changes: 44 additions & 0 deletions core/include/signed_hdr.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
enum shdr_img_type {
SHDR_TA = 0,
SHDR_BOOTSTRAP_TA = 1,
SHDR_ENCRYPTED_TA = 2,
};

#define SHDR_MAGIC 0x4f545348
Expand Down Expand Up @@ -57,6 +58,49 @@ struct shdr_bootstrap_ta {
uint32_t ta_version;
};

/**
* struct shdr_encrypted_ta - encrypted TA header
* @enc_algo: authenticated encyption algorithm, defined by symmetric key
* algorithms TEE_ALG_* from TEE Internal API
* specification
* @flags: authenticated encyption flags
* @iv_size: size of the initialization vector
* @tag_size: size of the authentication tag
* @iv: initialization vector
* @tag: authentication tag
*/
struct shdr_encrypted_ta {
uint32_t enc_algo;
uint32_t flags;
uint16_t iv_size;
uint16_t tag_size;
/*
* Commented out element used to visualize the layout dynamic part
* of the struct.
*
* iv is accessed through the macro SHDR_ENC_GET_IV and
* tag is accessed through the macro SHDR_ENC_GET_TAG
*
* uint8_t iv[iv_size];
* uint8_t tag[tag_size];
*/
};

#define SHDR_ENC_KEY_TYPE_MASK 0x1

enum shdr_enc_key_type {
SHDR_ENC_KEY_DEV_SPECIFIC = 0,
SHDR_ENC_KEY_CLASS_WIDE = 1,
};

#define SHDR_ENC_GET_SIZE(x) ({ typeof(x) _x = (x); \
(sizeof(struct shdr_encrypted_ta) + \
_x->iv_size + _x->tag_size); })
#define SHDR_ENC_GET_IV(x) ((uint8_t *) \
(((struct shdr_encrypted_ta *)(x)) + 1))
#define SHDR_ENC_GET_TAG(x) ({ typeof(x) _x = (x); \
(SHDR_ENC_GET_IV(_x) + _x->iv_size); })

/*
* Allocates a struct shdr large enough to hold the entire header,
* excluding a subheader like struct shdr_bootstrap_ta.
Expand Down
22 changes: 22 additions & 0 deletions core/include/tee/tee_ta_enc_manager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2019, Linaro Limited
*/

#ifndef TEE_TA_ENC_MANAGER_H
#define TEE_TA_ENC_MANAGER_H

#include <signed_hdr.h>
#include <tee_api_types.h>
#include <utee_defines.h>

#define TEE_TA_ENC_KEY_SIZE TEE_SHA256_HASH_SIZE

TEE_Result tee_ta_decrypt_init(void **enc_ctx, struct shdr_encrypted_ta *ehdr,
size_t len);
TEE_Result tee_ta_decrypt_update(void *enc_ctx, uint8_t *dst, uint8_t *src,
size_t len);
TEE_Result tee_ta_decrypt_final(void *enc_ctx, struct shdr_encrypted_ta *ehdr,
uint8_t *dst, uint8_t *src, size_t len);

#endif
1 change: 1 addition & 0 deletions core/tee/sub.mk
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ srcs-$(CFG_GP_SOCKETS) += socket.c
endif #CFG_WITH_USER_TA,y

srcs-y += uuid.c
srcs-y += tee_ta_enc_manager.c
Loading

0 comments on commit e1afc43

Please sign in to comment.