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/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__":