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)))