TA dev kit: add support for TA encryption
Add CFG_ENCRYPT_TA as TA build time configuration option to enable
encryption of TA using encryption key provided via TA_ENC_KEY build
time option. The default value of TA_ENC_KEY is derived from 16 zero
bytes default hardware unique key.
Also rename scripts/sign.py to scripts/sign_encrypt.py to reflect
optional encryption support along with signing of TAs.
Signed-off-by: Sumit Garg <sumit.garg@linaro.org>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/mk/lib.mk b/mk/lib.mk
index 13ace45..c5d07a2 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -43,7 +43,7 @@
libnames := $(libname) $(libnames)
libdeps := $(lib-libfile) $(libdeps)
-SIGN = scripts/sign.py
+SIGN = scripts/sign_encrypt.py
TA_SIGN_KEY ?= keys/default_ta.pem
define process-lib
diff --git a/scripts/sign.py b/scripts/sign_encrypt.py
similarity index 78%
rename from scripts/sign.py
rename to scripts/sign_encrypt.py
index 2939c59..0b3408d 100755
--- a/scripts/sign.py
+++ b/scripts/sign_encrypt.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
-#
-# Copyright (c) 2015, 2017, Linaro Limited
-#
# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2015, 2017, 2019, Linaro Limited
+#
import sys
@@ -19,7 +19,7 @@
def get_args(logger):
from argparse import ArgumentParser, RawDescriptionHelpFormatter
import textwrap
- command_base = ['sign', 'digest', 'stitch']
+ command_base = ['sign-enc', 'digest', 'stitch']
command_aliases_digest = ['generate-digest']
command_aliases_stitch = ['stitch-ta']
command_aliases = command_aliases_digest + command_aliases_stitch
@@ -29,26 +29,31 @@
sat = '[' + ', '.join(command_aliases_stitch) + ']'
parser = ArgumentParser(
- description='Sign a Tusted Application for OP-TEE.',
+ description='Sign and encrypt (optional) a Tusted Application for' +
+ ' OP-TEE.',
usage='\n %(prog)s command [ arguments ]\n\n'
' command:\n' +
- ' sign Generate signed loadable TA image file.\n' +
- ' Takes arguments --uuid, --ta-version, --in, --out' +
- ' and --key.\n' +
+ ' sign-enc Generate signed and optionally encrypted loadable' +
+ ' TA image file.\n' +
+ ' Takes arguments --uuid, --ta-version, --in, --out,' +
+ ' --key\n' +
+ ' and --enc-key (optional).\n' +
' digest Generate loadable TA binary image digest' +
' for offline\n' +
- ' signing. Takes arguments --uuid, --ta-version,' +
- ' --in, --key and --dig.\n' +
- ' stitch Generate loadable signed TA binary image' +
- ' file from\n' +
+ ' signing. Takes arguments --uuid, --ta-version,' +
+ ' --in, --key,\n'
+ ' --enc-key (optional) and --dig.\n' +
+ ' stitch Generate loadable signed and encrypted TA binary' +
+ ' image file from\n' +
' TA raw image and its signature. Takes' +
' arguments\n' +
- ' --uuid, --in, --key, --out, and --sig.\n\n' +
+ ' --uuid, --in, --key, --enc-key (optional), --out,' +
+ ' and --sig.\n\n' +
' %(prog)s --help show available commands and arguments\n\n',
formatter_class=RawDescriptionHelpFormatter,
epilog=textwrap.dedent('''\
- If no command is given, the script will default to "sign".
+ If no command is given, the script will default to "sign-enc".
command aliases:
The command \'digest\' can be aliased by ''' + dat + '''
@@ -63,12 +68,14 @@
parser.add_argument(
'command', choices=command_choices, nargs='?',
- default='sign',
+ default='sign-enc',
help='Command, one of [' + ', '.join(command_base) + ']')
parser.add_argument('--uuid', required=True,
type=uuid_parse, help='String UUID of the TA')
parser.add_argument('--key', required=True,
- help='Name of key file (PEM format)')
+ help='Name of signing key file (PEM format)')
+ parser.add_argument('--enc-key', required=False,
+ help='Encryption key string')
parser.add_argument(
'--ta-version', required=False, type=int_parse, default=0,
help='TA version stored as a 32-bit unsigned integer and used for\n' +
@@ -156,7 +163,10 @@
hdr_version = args.ta_version # struct shdr_bootstrap_ta::ta_version
magic = 0x4f545348 # SHDR_MAGIC
- img_type = 1 # SHDR_BOOTSTRAP_TA
+ if args.enc_key:
+ img_type = 2 # SHDR_ENCRYPTED_TA
+ else:
+ img_type = 1 # SHDR_BOOTSTRAP_TA
algo = 0x70004830 # TEE_ALG_RSASSA_PKCS1_V1_5_SHA256
shdr = struct.pack('<IIIIHH',
@@ -164,9 +174,23 @@
shdr_uuid = args.uuid.bytes
shdr_version = struct.pack('<I', hdr_version)
+ if args.enc_key:
+ from Cryptodome.Cipher import AES
+ cipher = AES.new(bytearray.fromhex(args.enc_key), AES.MODE_GCM)
+ ciphertext, tag = cipher.encrypt_and_digest(img)
+
+ enc_algo = 0x40000810 # TEE_ALG_AES_GCM
+ flags = 0 # SHDR_ENC_KEY_DEV_SPECIFIC
+ ehdr = struct.pack('<IIHH',
+ enc_algo, flags, len(cipher.nonce), len(tag))
+
h.update(shdr)
h.update(shdr_uuid)
h.update(shdr_version)
+ if args.enc_key:
+ h.update(ehdr)
+ h.update(cipher.nonce)
+ h.update(tag)
h.update(img)
img_digest = h.digest()
@@ -177,9 +201,15 @@
f.write(sig)
f.write(shdr_uuid)
f.write(shdr_version)
- f.write(img)
+ if args.enc_key:
+ f.write(ehdr)
+ f.write(cipher.nonce)
+ f.write(tag)
+ f.write(ciphertext)
+ else:
+ f.write(img)
- def sign_ta():
+ def sign_encrypt_ta():
if not key.has_private():
logger.error('Provided key cannot be used for signing, ' +
'please use offline-signing mode.')
@@ -222,12 +252,12 @@
# dispatch command
{
- 'sign': sign_ta,
+ 'sign-enc': sign_encrypt_ta,
'digest': generate_digest,
'generate-digest': generate_digest,
'stitch': stitch_ta,
'stitch-ta': stitch_ta
- }.get(args.command, 'sign_ta')()
+ }.get(args.command, 'sign_encrypt_ta')()
if __name__ == "__main__":
diff --git a/ta/arch/arm/link.mk b/ta/arch/arm/link.mk
index 247d45b..4564352 100644
--- a/ta/arch/arm/link.mk
+++ b/ta/arch/arm/link.mk
@@ -2,9 +2,20 @@
link-script-pp$(sm) = $(link-out-dir$(sm))/ta.lds
link-script-dep$(sm) = $(link-out-dir$(sm))/.ta.ld.d
-SIGN ?= $(ta-dev-kit-dir$(sm))/scripts/sign.py
+SIGN_ENC ?= $(ta-dev-kit-dir$(sm))/scripts/sign_encrypt.py
TA_SIGN_KEY ?= $(ta-dev-kit-dir$(sm))/keys/default_ta.pem
+ifeq ($(CFG_ENCRYPT_TA),y)
+# Default TA encryption key is a dummy key derived from default
+# hardware unique key (an array of 16 zero bytes) to demonstrate
+# usage of REE-FS TAs encryption feature.
+#
+# Note that a user of this TA encryption feature needs to provide
+# encryption key and its handling corresponding to their security
+# requirements.
+TA_ENC_KEY ?= 'b64d239b1f3c7d3b06506229cd8ff7c8af2bb4db2168621ac62c84948468c4f4'
+endif
+
all: $(link-out-dir$(sm))/$(user-ta-uuid).dmp \
$(link-out-dir$(sm))/$(user-ta-uuid).stripped.elf \
$(link-out-dir$(sm))/$(user-ta-uuid).ta
@@ -72,12 +83,17 @@
@$(cmd-echo-silent) ' OBJCOPY $$@'
$(q)$(OBJCOPY$(sm)) --strip-unneeded $$< $$@
+cmd-echo$(user-ta-uuid) := SIGN #
+ifeq ($(CFG_ENCRYPT_TA),y)
+crypt-args$(user-ta-uuid) := --enc-key $(TA_ENC_KEY)
+cmd-echo$(user-ta-uuid) := SIGNENC
+endif
$(link-out-dir$(sm))/$(user-ta-uuid).ta: \
$(link-out-dir$(sm))/$(user-ta-uuid).stripped.elf \
$(TA_SIGN_KEY)
- @$(cmd-echo-silent) ' SIGN $$@'
- $(q)$(SIGN) --key $(TA_SIGN_KEY) --uuid $(user-ta-uuid) \
- --in $$< --out $$@
+ @$(cmd-echo-silent) ' $$(cmd-echo$(user-ta-uuid)) $$@'
+ $(q)$(SIGN_ENC) --key $(TA_SIGN_KEY) $$(crypt-args$(user-ta-uuid)) \
+ --uuid $(user-ta-uuid) --in $$< --out $$@
endef
$(eval $(call gen-link-t))
diff --git a/ta/arch/arm/link_shlib.mk b/ta/arch/arm/link_shlib.mk
index d4d7134..4dae337 100644
--- a/ta/arch/arm/link_shlib.mk
+++ b/ta/arch/arm/link_shlib.mk
@@ -3,7 +3,7 @@
endif
link-out-dir = $(out-dir)
-SIGN ?= $(TA_DEV_KIT_DIR)/scripts/sign.py
+SIGN ?= $(TA_DEV_KIT_DIR)/scripts/sign_encrypt.py
TA_SIGN_KEY ?= $(TA_DEV_KIT_DIR)/keys/default_ta.pem
all: $(link-out-dir)/$(shlibname).so $(link-out-dir)/$(shlibname).dmp \
diff --git a/ta/ta.mk b/ta/ta.mk
index 1278670..522ab29 100644
--- a/ta/ta.mk
+++ b/ta/ta.mk
@@ -192,7 +192,8 @@
$(eval $(call copy-file, $(f), $(out-dir)/export-$(sm)/keys)))
# Copy the scripts
-ta-scripts = scripts/sign.py scripts/symbolize.py scripts/llvm-objcopy-wrapper
+ta-scripts = scripts/sign_encrypt.py scripts/symbolize.py \
+ scripts/llvm-objcopy-wrapper
$(foreach f, $(ta-scripts), \
$(eval $(call copy-file, $(f), $(out-dir)/export-$(sm)/scripts)))