blob: b8ac2c0100103ae296578c20c62f39fc28faa87c [file] [log] [blame]
Rouven Czerwinskibbaeed42019-08-07 20:07:00 +02001#!/usr/bin/env python3
Jens Wiklandercd5cf432017-11-28 16:59:15 +01002# SPDX-License-Identifier: BSD-2-Clause
Sumit Garg2de17fd2019-10-23 12:47:24 +05303#
4# Copyright (c) 2015, 2017, 2019, Linaro Limited
5#
Jens Wiklandercd5cf432017-11-28 16:59:15 +01006
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +02007import sys
Donald Chan169eac12021-10-24 14:22:54 -07008import math
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +02009
Jerome Forissier4a477922018-11-14 11:02:49 +010010
Jens Wiklander49e93632022-10-04 11:25:22 +020011sig_tee_alg = {'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256': 0x70414930,
12 'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256': 0x70004830}
13
14enc_tee_alg = {'TEE_ALG_AES_GCM': 0x40000810}
Mingyuan Xiangcf3d6ac2020-09-17 19:01:02 +080015
Donald Chanc45a84b2022-01-01 22:32:45 +000016enc_key_type = {'SHDR_ENC_KEY_DEV_SPECIFIC': 0x0,
17 'SHDR_ENC_KEY_CLASS_WIDE': 0x1}
18
Donald Chana797f202022-01-10 19:31:13 +000019SHDR_BOOTSTRAP_TA = 1
20SHDR_ENCRYPTED_TA = 2
21SHDR_MAGIC = 0x4f545348
22SHDR_SIZE = 20
Jens Wiklander49e93632022-10-04 11:25:22 +020023EHDR_SIZE = 12
24UUID_SIZE = 16
25# Use 12 bytes for nonce per recommendation
26NONCE_SIZE = 12
27TAG_SIZE = 16
28
29
30def value_to_key(db, val):
31 for k, v in db.items():
32 if v == val:
33 return k
Donald Chana797f202022-01-10 19:31:13 +000034
Mingyuan Xiangcf3d6ac2020-09-17 19:01:02 +080035
Jens Wiklandercd5cf432017-11-28 16:59:15 +010036def uuid_parse(s):
37 from uuid import UUID
38 return UUID(s)
39
40
41def int_parse(str):
42 return int(str, 0)
43
Jens Wiklanderbc420742015-05-05 14:59:15 +020044
Jens Wiklander5e153002022-10-06 11:43:54 +020045def get_args():
Jens Wiklanderf182afc2022-10-04 10:19:27 +020046 def arg_add_uuid(parser):
47 parser.add_argument(
48 '--uuid', required=True, type=uuid_parse,
49 help='String UUID of the TA')
50
51 def arg_add_key(parser):
52 parser.add_argument(
53 '--key', required=True, help='''
54 Name of signing and verification key file (PEM format) or an
55 Amazon Resource Name (arn:) of an AWS KMS asymmetric key.
56 At least public key for the commands digest, stitch, and
57 verify, else a private key''')
58
59 def arg_add_enc_key(parser):
60 parser.add_argument(
61 '--enc-key', required=False, help='Encryption key string')
62
63 def arg_add_enc_key_type(parser):
64 parser.add_argument(
65 '--enc-key-type', required=False,
66 default='SHDR_ENC_KEY_DEV_SPECIFIC',
67 choices=list(enc_key_type.keys()), help='''
68 Encryption key type,
69 Defaults to SHDR_ENC_KEY_DEV_SPECIFIC.''')
70
71 def arg_add_ta_version(parser):
72 parser.add_argument(
73 '--ta-version', required=False, type=int_parse, default=0, help='''
74 TA version stored as a 32-bit unsigned integer and used for
75 rollback protection of TA install in the secure database.
76 Defaults to 0.''')
77
78 def arg_add_sig(parser):
79 parser.add_argument(
80 '--sig', required=True, dest='sigf',
81 help='Name of signature input file, defaults to <UUID>.sig')
82
83 def arg_add_dig(parser):
84 parser.add_argument(
85 '--dig', required=True, dest='digf',
86 help='Name of digest output file, defaults to <UUID>.dig')
87
88 def arg_add_in(parser):
89 parser.add_argument(
90 '--in', required=False, dest='inf', help='''
91 Name of application input file, defaults to
92 <UUID>.stripped.elf''')
93
94 def arg_add_out(parser):
95 parser.add_argument(
96 '--out', required=True, dest='outf',
97 help='Name of application output file, defaults to <UUID>.ta')
98
99 def arg_add_algo(parser):
100 parser.add_argument(
Jens Wiklander49e93632022-10-04 11:25:22 +0200101 '--algo', required=False, choices=list(sig_tee_alg.keys()),
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200102 default='TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256', help='''
103 The hash and signature algorithm.
104 Defaults to TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256.''')
105
106 def get_outf_default(parsed):
107 return str(parsed.uuid) + '.ta'
108
109 def get_inf_default(parsed):
110 return str(parsed.uuid) + '.stripped.elf'
111
112 def get_sigf_default(parsed):
113 return str(parsed.uuid) + '.sig'
114
115 def get_digf_default(parsed):
116 return str(parsed.uuid) + '.dig'
117
118 def assign_default_value(parsed, attr, func):
119 if hasattr(parsed, attr) and getattr(parsed, attr) is None:
120 setattr(parsed, attr, func(parsed))
121
122 import argparse
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200123 import textwrap
Jens Wiklanderbc420742015-05-05 14:59:15 +0200124
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200125 parser = argparse.ArgumentParser(
126 description='Sign and encrypt (optional) a Trusted Application ' +
127 ' for OP-TEE.',
128 usage='%(prog)s <command> ...',
129 epilog='<command> -h for detailed help')
130 subparsers = parser.add_subparsers(
131 title='valid commands, with possible aliases in ()',
132 dest='command', metavar='')
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200133
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200134 parser_sign_enc = subparsers.add_parser(
135 'sign-enc', prog=parser.prog + ' sign-enc',
136 help='Generate signed and optionally encrypted loadable TA image file')
Jens Wiklander3cf28232022-10-06 10:00:25 +0200137 parser_sign_enc.set_defaults(func=command_sign_enc)
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200138 arg_add_uuid(parser_sign_enc)
139 arg_add_ta_version(parser_sign_enc)
140 arg_add_in(parser_sign_enc)
141 arg_add_out(parser_sign_enc)
142 arg_add_key(parser_sign_enc)
143 arg_add_enc_key(parser_sign_enc)
144 arg_add_enc_key_type(parser_sign_enc)
145 arg_add_algo(parser_sign_enc)
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200146
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200147 parser_digest = subparsers.add_parser(
148 'digest', aliases=['generate-digest'], prog=parser.prog + ' digest',
149 formatter_class=argparse.RawDescriptionHelpFormatter,
150 help='Generate loadable TA binary image digest for offline signing',
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200151 epilog=textwrap.dedent('''\
Mingyuan Xiangcf3d6ac2020-09-17 19:01:02 +0800152 example offline signing command using OpenSSL for algorithm
153 TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200154 base64 -d <UUID>.dig | \\
155 openssl pkeyutl -sign -inkey <KEYFILE>.pem \\
Mingyuan Xiangcf3d6ac2020-09-17 19:01:02 +0800156 -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss \\
157 -pkeyopt rsa_pss_saltlen:digest \\
158 -pkeyopt rsa_mgf1_md:sha256 | \\
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200159 base64 > <UUID>.sig
160
Mingyuan Xiangcf3d6ac2020-09-17 19:01:02 +0800161 example offline signing command using OpenSSL for algorithm
162 TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
163 base64 -d <UUID>.dig | \\
164 openssl pkeyutl -sign -inkey <KEYFILE>.pem \\
165 -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pkcs1 | \\
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200166 base64 > <UUID>.sig
167 '''))
Jens Wiklander3cf28232022-10-06 10:00:25 +0200168 parser_digest.set_defaults(func=command_digest)
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200169 arg_add_uuid(parser_digest)
170 arg_add_ta_version(parser_digest)
171 arg_add_in(parser_digest)
172 arg_add_key(parser_digest)
173 arg_add_enc_key(parser_digest)
174 arg_add_enc_key_type(parser_digest)
175 arg_add_algo(parser_digest)
176 arg_add_dig(parser_digest)
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200177
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200178 parser_stitch = subparsers.add_parser(
179 'stitch', aliases=['stitch-ta'], prog=parser.prog + ' stich',
180 help='Generate loadable signed and encrypted TA binary image file' +
181 ' from TA raw image and its signature')
Jens Wiklander3cf28232022-10-06 10:00:25 +0200182 parser_stitch.set_defaults(func=command_stitch)
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200183 arg_add_uuid(parser_stitch)
184 arg_add_ta_version(parser_stitch)
185 arg_add_in(parser_stitch)
186 arg_add_key(parser_stitch)
187 arg_add_out(parser_stitch)
188 arg_add_enc_key(parser_stitch)
189 arg_add_enc_key_type(parser_stitch)
190 arg_add_algo(parser_stitch)
191 arg_add_sig(parser_stitch)
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200192
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200193 parser_verify = subparsers.add_parser(
194 'verify', prog=parser.prog + ' verify',
195 help='Verify signed TA binary')
Jens Wiklander3cf28232022-10-06 10:00:25 +0200196 parser_verify.set_defaults(func=command_verify)
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200197 arg_add_uuid(parser_verify)
198 arg_add_in(parser_verify)
199 arg_add_key(parser_verify)
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200200
Jens Wiklanderf4549882022-10-06 14:44:08 +0200201 parser_display = subparsers.add_parser(
202 'display', prog=parser.prog + ' display',
203 help='Parses and displays a signed TA binary')
204 parser_display.set_defaults(func=command_display)
205 arg_add_in(parser_display)
206
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200207 argv = sys.argv[1:]
208 if (len(argv) > 0 and argv[0][0] == '-' and
209 argv[0] != '-h' and argv[0] != '--help'):
210 # The default sub-command is 'sign-enc' so add it to the parser
211 # if one is missing
212 argv = ['sign-enc'] + argv
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200213
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200214 parsed = parser.parse_args(argv)
215
216 if parsed.command is None:
217 parser.print_help()
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200218 sys.exit(1)
219
Jens Wiklanderf182afc2022-10-04 10:19:27 +0200220 # Set a few defaults if defined for the current command
221 assign_default_value(parsed, 'inf', get_inf_default)
222 assign_default_value(parsed, 'outf', get_outf_default)
223 assign_default_value(parsed, 'sigf', get_sigf_default)
224 assign_default_value(parsed, 'digf', get_digf_default)
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200225
226 return parsed
Jens Wiklandercd5cf432017-11-28 16:59:15 +0100227
Jens Wiklanderbc420742015-05-05 14:59:15 +0200228
Jens Wiklander49e93632022-10-04 11:25:22 +0200229def load_asymmetric_key(arg_key):
230 if arg_key.startswith('arn:'):
Donald Chan05c007f2022-01-05 17:54:00 +0000231 from sign_helper_kms import _RSAPrivateKeyInKMS
Jens Wiklander49e93632022-10-04 11:25:22 +0200232 key = _RSAPrivateKeyInKMS(arg_key)
Donald Chan05c007f2022-01-05 17:54:00 +0000233 else:
Jens Wiklander49e93632022-10-04 11:25:22 +0200234 from cryptography.hazmat.backends import default_backend
235 from cryptography.hazmat.primitives.serialization import (
236 load_pem_private_key, load_pem_public_key)
237
238 with open(arg_key, 'rb') as f:
Donald Chan05c007f2022-01-05 17:54:00 +0000239 data = f.read()
Donald Chan169eac12021-10-24 14:22:54 -0700240
Donald Chan05c007f2022-01-05 17:54:00 +0000241 try:
Jens Wiklander49e93632022-10-04 11:25:22 +0200242 key = load_pem_private_key(data, password=None,
243 backend=default_backend())
Donald Chan05c007f2022-01-05 17:54:00 +0000244 except ValueError:
Jens Wiklander49e93632022-10-04 11:25:22 +0200245 key = load_pem_public_key(data, backend=default_backend())
Jens Wiklanderbc420742015-05-05 14:59:15 +0200246
Jens Wiklander49e93632022-10-04 11:25:22 +0200247 return key
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200248
Jens Wiklanderbc420742015-05-05 14:59:15 +0200249
Jens Wiklander49e93632022-10-04 11:25:22 +0200250class BinaryImage:
251 def __init__(self, arg_inf, arg_key):
252 from cryptography.hazmat.primitives import hashes
Volodymyr Babchuk90ad2452019-08-21 21:00:32 +0300253
Jens Wiklander49e93632022-10-04 11:25:22 +0200254 # Exactly what inf is holding isn't determined a this stage
255 with open(arg_inf, 'rb') as f:
256 self.inf = f.read()
Jens Wiklanderbc420742015-05-05 14:59:15 +0200257
Jens Wiklanderf4549882022-10-06 14:44:08 +0200258 if arg_key is None:
259 self.key = None
260 else:
261 self.key = load_asymmetric_key(arg_key)
262 self.sig_len = math.ceil(self.key.key_size / 8)
Etienne Carriere47844622019-08-12 11:33:24 +0200263
Jens Wiklander49e93632022-10-04 11:25:22 +0200264 self.chosen_hash = hashes.SHA256()
265 self.digest_len = self.chosen_hash.digest_size
Etienne Carriere47844622019-08-12 11:33:24 +0200266
Jens Wiklander49e93632022-10-04 11:25:22 +0200267 def __pack_img(self, img_type, sign_algo):
268 import struct
Jens Wiklanderbc420742015-05-05 14:59:15 +0200269
Jens Wiklander49e93632022-10-04 11:25:22 +0200270 self.sig_algo = sign_algo
271 self.img_type = img_type
272 self.shdr = struct.pack('<IIIIHH', SHDR_MAGIC, img_type, len(self.img),
273 sig_tee_alg[sign_algo], self.digest_len,
274 self.sig_len)
275
276 def __calc_digest(self):
277 from cryptography.hazmat.backends import default_backend
278 from cryptography.hazmat.primitives import hashes
279
280 h = hashes.Hash(self.chosen_hash, default_backend())
281 h.update(self.shdr)
282 h.update(self.ta_uuid)
283 h.update(self.ta_version)
284 if hasattr(self, 'ehdr'):
285 h.update(self.ehdr)
286 h.update(self.nonce)
287 h.update(self.tag)
288 h.update(self.img)
289 return h.finalize()
290
291 def encrypt_ta(self, enc_key, key_type, sig_algo, uuid, ta_version):
Donald Chan169eac12021-10-24 14:22:54 -0700292 from cryptography.hazmat.primitives.ciphers.aead import AESGCM
Jens Wiklander49e93632022-10-04 11:25:22 +0200293 import struct
294 import os
Sumit Garg2de17fd2019-10-23 12:47:24 +0530295
Jens Wiklander49e93632022-10-04 11:25:22 +0200296 self.img = self.inf
Sumit Garg2de17fd2019-10-23 12:47:24 +0530297
Jens Wiklander49e93632022-10-04 11:25:22 +0200298 cipher = AESGCM(bytes.fromhex(enc_key))
299 self.nonce = os.urandom(NONCE_SIZE)
300 out = cipher.encrypt(self.nonce, self.img, None)
301 self.ciphertext = out[:-TAG_SIZE]
302 # Authentication Tag is always the last bytes
303 self.tag = out[-TAG_SIZE:]
Jens Wiklanderbc420742015-05-05 14:59:15 +0200304
Jens Wiklander49e93632022-10-04 11:25:22 +0200305 enc_algo = enc_tee_alg['TEE_ALG_AES_GCM']
306 flags = enc_key_type[key_type]
307 self.ehdr = struct.pack('<IIHH', enc_algo, flags, len(self.nonce),
308 len(self.tag))
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200309
Jens Wiklander49e93632022-10-04 11:25:22 +0200310 self.__pack_img(SHDR_ENCRYPTED_TA, sig_algo)
311 self.ta_uuid = uuid.bytes
312 self.ta_version = struct.pack('<I', ta_version)
313 self.img_digest = self.__calc_digest()
Donald Chan169eac12021-10-24 14:22:54 -0700314
Jens Wiklander49e93632022-10-04 11:25:22 +0200315 def set_bootstrap_ta(self, sig_algo, uuid, ta_version):
316 import struct
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200317
Jens Wiklander49e93632022-10-04 11:25:22 +0200318 self.img = self.inf
319 self.__pack_img(SHDR_BOOTSTRAP_TA, sig_algo)
320 self.ta_uuid = uuid.bytes
321 self.ta_version = struct.pack('<I', ta_version)
322 self.img_digest = self.__calc_digest()
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200323
Jens Wiklander49e93632022-10-04 11:25:22 +0200324 def parse(self):
325 import struct
Markus S. Wamser1cdd95a2019-04-30 12:03:12 +0200326
Jens Wiklander49e93632022-10-04 11:25:22 +0200327 offs = 0
328 self.shdr = self.inf[offs:offs + SHDR_SIZE]
329 [magic, img_type, img_size, algo_value, digest_len,
330 sig_len] = struct.unpack('<IIIIHH', self.shdr)
331 offs += SHDR_SIZE
Donald Chan51eee1e2022-01-11 18:54:25 +0000332
333 if magic != SHDR_MAGIC:
334 raise Exception("Unexpected magic: 0x{:08x}".format(magic))
335
Jens Wiklander49e93632022-10-04 11:25:22 +0200336 if algo_value not in sig_tee_alg.values():
Donald Chan51eee1e2022-01-11 18:54:25 +0000337 raise Exception('Unrecognized algorithm: 0x{:08x}'
338 .format(algo_value))
Jens Wiklander49e93632022-10-04 11:25:22 +0200339 self.sig_algo = value_to_key(sig_tee_alg, algo_value)
Donald Chan51eee1e2022-01-11 18:54:25 +0000340
Jens Wiklander49e93632022-10-04 11:25:22 +0200341 if digest_len != self.digest_len:
342 raise Exception("Unexpected digest len: {}".format(digest_len))
343
344 self.img_digest = self.inf[offs:offs + digest_len]
345 offs += digest_len
346 self.sig = self.inf[offs:offs + sig_len]
347 offs += sig_len
348
349 if img_type == SHDR_BOOTSTRAP_TA or img_type == SHDR_ENCRYPTED_TA:
350 self.ta_uuid = self.inf[offs:offs + UUID_SIZE]
351 offs += UUID_SIZE
352 self.ta_version = self.inf[offs:offs + 4]
353 offs += 4
354 if img_type == SHDR_ENCRYPTED_TA:
355 self.ehdr = self.inf[offs: offs + EHDR_SIZE]
356 offs += EHDR_SIZE
357 [enc_algo, flags, nonce_len,
358 tag_len] = struct.unpack('<IIHH', self.ehdr)
359 if enc_value not in enc_tee_alg.values():
360 raise Exception('Unrecognized encrypt algorithm: 0x{:08x}'
361 .format(enc_value))
362 if nonce_len != 12:
363 raise Exception("Unexpected nonce len: {}"
364 .format(nonce_len))
365 self.nonce = self.inf[offs:offs + nonce_len]
366 offs += nonce_len
367
368 if tag_len != 16:
369 raise Exception("Unexpected tag len: {}".format(tag_len))
370 self.tag = self.inf[-tag_len:]
371 self.ciphertext = self.inf[offs:-tag_len]
372 if len(self.ciphertext) != img_size:
373 raise Exception("Unexpected ciphertext size: ",
374 "got {}, expected {}"
375 .format(len(self.ciphertext), img_size))
376 else:
377 self.img = self.inf[offs:]
378 if len(self.img) != img_size:
379 raise Exception("Unexpected img size: got {}, expected {}"
380 .format(len(self.img), img_size))
Donald Chan51eee1e2022-01-11 18:54:25 +0000381 else:
Jens Wiklander49e93632022-10-04 11:25:22 +0200382 raise Exception("Unsupported image type: {}".format(img_type))
Donald Chan51eee1e2022-01-11 18:54:25 +0000383
Jens Wiklanderf4549882022-10-06 14:44:08 +0200384 def display(self):
385 import binascii
386 import struct
387 import uuid
388
389 offs = 0
390 shdr = self.inf[offs:offs + SHDR_SIZE]
391 [magic, img_type, img_size, algo_value, digest_len,
392 sig_len] = struct.unpack('<IIIIHH', shdr)
393 offs += SHDR_SIZE
394
395 if magic != SHDR_MAGIC:
396 Exception("Unexpected magic: 0x{:08x}".format(magic))
397
398 img_type_name = 'Unknown'
399 if img_type == SHDR_BOOTSTRAP_TA:
400 print('Bootstrap TA')
401 img_type_name = 'SHDR_BOOTSTRAP_TA'
402 if img_type == SHDR_ENCRYPTED_TA:
403 print('Encrypted TA')
404 img_type_name = 'SHDR_ENCRYPTED_TA'
405
406 algo_name = 'Unknown'
407 if algo_value in sig_tee_alg.values():
408 algo_name = value_to_key(sig_tee_alg, algo_value)
409
410 print(' struct shdr')
411 print(' magic: 0x{:08x}'.format(magic))
412 print(' img_type: {} ({})'.format(img_type, img_type_name))
413 print(' img_size: {} bytes'.format(img_size))
414 print(' algo: 0x{:08x} ({})'.format(algo_value, algo_name))
415 print(' hash_size: {} bytes'.format(digest_len))
416 print(' sig_size: {} bytes'.format(sig_len))
417
418 if algo_value not in sig_tee_alg.values():
419 raise Exception('Unrecognized algorithm: 0x{:08x}'
420 .format(algo_value))
421
422 if digest_len != self.digest_len:
423 raise Exception("Unexpected digest len: {}".format(digest_len))
424
425 img_digest = self.inf[offs:offs + digest_len]
426 print(' hash: {}'
427 .format(binascii.hexlify(img_digest).decode('ascii')))
428 offs += digest_len
429 sig = self.inf[offs:offs + sig_len]
430 offs += sig_len
431
432 if img_type == SHDR_BOOTSTRAP_TA or img_type == SHDR_ENCRYPTED_TA:
433 print(' struct shdr_bootstrap_ta')
434 ta_uuid = self.inf[offs:offs + UUID_SIZE]
435 print(' uuid: {}'.format(uuid.UUID(bytes=ta_uuid)))
436 offs += UUID_SIZE
437 [ta_version] = struct.unpack('<I', self.inf[offs:offs + 4])
438 print(' ta_version: {}'.format(ta_version))
439
440 offs += 4
441 if img_type == SHDR_ENCRYPTED_TA:
442 ehdr = self.inf[offs: offs + EHDR_SIZE]
443 offs += EHDR_SIZE
444 [enc_algo, flags, nonce_len,
445 tag_len] = struct.unpack('<IIHH', ehdr)
446
447 print(' struct shdr_encrypted_ta')
448 enc_algo_name = 'Unkown'
449 if enc_algo in enc_tee_alg.values():
450 enc_algo_name = value_to_key(enc_tee_alg, enc_algo)
451 print(' enc_algo: 0x{:08x} ({})'
452 .format(enc_algo, enc_algo_name))
453
454 if enc_algo not in enc_tee_alg.values():
455 raise Exception('Unrecognized encrypt algorithm: 0x{:08x}'
456 .format(enc_value))
457
458 flags_name = 'Unkown'
459 if flags in enc_key_type.values():
460 flags_name = value_to_key(enc_key_type, flags)
461 print(' flags: 0x{:x} ({})'.format(flags, flags_name))
462
463 print(' iv_size: {} (bytes)'.format(nonce_len))
464 if nonce_len != NONCE_SIZE:
465 raise Exception("Unexpected nonce len: {}"
466 .format(nonce_len))
467 nonce = self.inf[offs:offs + nonce_len]
468 print(' iv: {}'
469 .format(binascii.hexlify(nonce).decode('ascii')))
470 offs += nonce_len
471
472 print(' tag_size: {} (bytes)'.format(tag_len))
473 if tag_len != TAG_SIZE:
474 raise Exception("Unexpected tag len: {}".format(tag_len))
475 tag = self.inf[-tag_len:]
476 print(' tag: {}'
477 .format(binascii.hexlify(tag).decode('ascii')))
478 ciphertext = self.inf[offs:-tag_len]
479 print(' TA offset: {} (0x{:x}) bytes'.format(offs, offs))
480 print(' TA size: {} (0x{:x}) bytes'
481 .format(len(ciphertext), len(ciphertext)))
482 if len(ciphertext) != img_size:
483 raise Exception("Unexpected ciphertext size: ",
484 "got {}, expected {}"
485 .format(len(ciphertext), img_size))
486 offs += tag_len
487 else:
488 img = self.inf[offs:]
489 print(' TA offset: {} (0x{:x}) bytes'.format(offs, offs))
490 print(' TA size: {} (0x{:x}) bytes'
491 .format(len(img), len(img)))
492 if len(img) != img_size:
493 raise Exception("Unexpected img size: got {}, expected {}"
494 .format(len(img), img_size))
495 else:
496 raise Exception("Unsupported image type: {}".format(img_type))
497
Jens Wiklander49e93632022-10-04 11:25:22 +0200498 def decrypt_ta(enc_key):
499 from cryptography.hazmat.primitives.ciphers.aead import AESGCM
Donald Chan51eee1e2022-01-11 18:54:25 +0000500
Jens Wiklander49e93632022-10-04 11:25:22 +0200501 cipher = AESGCM(bytes.fromhex(enc_key))
502 self.img = cipher.decrypt(self.nonce, self.ciphertext, None)
Donald Chan51eee1e2022-01-11 18:54:25 +0000503
Jens Wiklander49e93632022-10-04 11:25:22 +0200504 def __get_padding(self):
505 from cryptography.hazmat.primitives.asymmetric import padding
Donald Chan51eee1e2022-01-11 18:54:25 +0000506
Jens Wiklander49e93632022-10-04 11:25:22 +0200507 if self.sig_algo == 'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256':
508 pad = padding.PSS(mgf=padding.MGF1(self.chosen_hash),
509 salt_length=self.digest_len)
510 elif self.sig_algo == 'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256':
511 pad = padding.PKCS1v15()
Donald Chan51eee1e2022-01-11 18:54:25 +0000512
Jens Wiklander49e93632022-10-04 11:25:22 +0200513 return pad
514
515 def sign(self):
516 from cryptography.hazmat.primitives.asymmetric import utils
517 from cryptography.hazmat.primitives.asymmetric import rsa
518
519 if not isinstance(self.key, rsa.RSAPrivateKey):
520 logger.error('Provided key cannot be used for signing, ' +
521 'please use offline-signing mode.')
522 sys.exit(1)
523 else:
524 self.sig = self.key.sign(self.img_digest, self.__get_padding(),
525 utils.Prehashed(self.chosen_hash))
526
527 if len(self.sig) != self.sig_len:
528 raise Exception(("Actual signature length is not equal to ",
529 "the computed one: {} != {}").
530 format(len(self.sig), self.sig_len))
531
532 def add_signature(self, sigf):
533 import base64
534
535 with open(sigf, 'r') as f:
536 self.sig = base64.b64decode(f.read())
537
538 if len(self.sig) != self.sig_len:
539 raise Exception(("Actual signature length is not equal to ",
540 "the expected one: {} != {}").
541 format(len(self.sig), self.sig_len))
542
543 def verify_signature(self):
544 from cryptography.hazmat.primitives.asymmetric import utils
545 from cryptography.hazmat.primitives.asymmetric import rsa
546 from cryptography import exceptions
547
548 if isinstance(self.key, rsa.RSAPrivateKey):
549 pkey = self.key.public_key()
550 else:
551 pkey = self.key
552
553 try:
554 pkey.verify(self.sig, self.img_digest, self.__get_padding(),
555 utils.Prehashed(self.chosen_hash))
556 except exceptions.InvalidSignature:
557 logger.error('Verification failed, ignoring given signature.')
558 sys.exit(1)
559
560 def verify_digest(self):
561 if self.img_digest != self.__calc_digest():
Donald Chan51eee1e2022-01-11 18:54:25 +0000562 raise Exception('Hash digest does not match')
563
Jens Wiklander49e93632022-10-04 11:25:22 +0200564 def verify_uuid(self, uuid):
565 if self.ta_uuid != uuid.bytes:
566 raise Exception('UUID does not match')
567
568 def write(self, outf):
569 with open(outf, 'wb') as f:
570 f.write(self.shdr)
571 f.write(self.img_digest)
572 f.write(self.sig)
573 f.write(self.ta_uuid)
574 f.write(self.ta_version)
575 if hasattr(self, 'ehdr'):
576 f.write(self.ehdr)
577 f.write(self.nonce)
578 f.write(self.tag)
579 f.write(self.ciphertext)
580 else:
581 f.write(self.img)
582
583
584def load_ta_image(args):
585 ta_image = BinaryImage(args.inf, args.key)
586
587 if args.enc_key:
588 ta_image.encrypt_ta(args.enc_key, args.enc_key_type,
589 args.algo, args.uuid, args.ta_version)
590 else:
591 ta_image.set_bootstrap_ta(args.algo, args.uuid, args.ta_version)
592
593 return ta_image
594
595
Jens Wiklander3cf28232022-10-06 10:00:25 +0200596def command_sign_enc(args):
597 ta_image = load_ta_image(args)
598 ta_image.sign()
599 ta_image.write(args.outf)
600 logger.info('Successfully signed application.')
601
602
603def command_digest(args):
604 import base64
605
606 ta_image = load_ta_image(args)
607 with open(args.digf, 'wb+') as digfile:
608 digfile.write(base64.b64encode(ta_image.img_digest))
609
610
611def command_stitch(args):
612 ta_image = load_ta_image(args)
613 ta_image.add_signature(args.sigf)
614 ta_image.verify_signature()
615 ta_image.write(args.outf)
616 logger.info('Successfully applied signature.')
617
618
619def command_verify(args):
620 ta_image = BinaryImage(args.inf, args.key)
621 ta_image.parse()
622 if hasattr(ta_image, 'ciphertext'):
623 if args.enc_key is None:
624 logger.error('--enc_key needed to decrypt TA')
625 sys.exit(1)
626 ta_image.decrypt_ta(args.enc_key)
627 ta_image.verify_signature()
628 ta_image.verify_digest()
629 ta_image.verify_uuid(args.uuid)
630 logger.info('Trusted application is correctly verified.')
631
632
Jens Wiklanderf4549882022-10-06 14:44:08 +0200633def command_display(args):
634 ta_image = BinaryImage(args.inf, None)
635 ta_image.display()
636
637
Jens Wiklander49e93632022-10-04 11:25:22 +0200638def main():
639 import logging
640 import os
641
642 global logger
643 logging.basicConfig()
644 logger = logging.getLogger(os.path.basename(__file__))
645
646 args = get_args()
Jens Wiklander3cf28232022-10-06 10:00:25 +0200647 args.func(args)
Jens Wiklandercd5cf432017-11-28 16:59:15 +0100648
Jens Wiklanderbc420742015-05-05 14:59:15 +0200649
650if __name__ == "__main__":
Jens Wiklandercd5cf432017-11-28 16:59:15 +0100651 main()