xref: /optee_os/scripts/sign_encrypt.py (revision f454988e7cd5715f8ad1c49024c8a7dc63dbc82f)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2015, 2017, 2019, Linaro Limited
5#
6
7import sys
8import math
9
10
11sig_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}
15
16enc_key_type = {'SHDR_ENC_KEY_DEV_SPECIFIC': 0x0,
17                'SHDR_ENC_KEY_CLASS_WIDE': 0x1}
18
19SHDR_BOOTSTRAP_TA = 1
20SHDR_ENCRYPTED_TA = 2
21SHDR_MAGIC = 0x4f545348
22SHDR_SIZE = 20
23EHDR_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
34
35
36def uuid_parse(s):
37    from uuid import UUID
38    return UUID(s)
39
40
41def int_parse(str):
42    return int(str, 0)
43
44
45def get_args():
46    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(
101            '--algo', required=False, choices=list(sig_tee_alg.keys()),
102            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
123    import textwrap
124
125    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='')
133
134    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')
137    parser_sign_enc.set_defaults(func=command_sign_enc)
138    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)
146
147    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',
151        epilog=textwrap.dedent('''\
152            example offline signing command using OpenSSL for algorithm
153            TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
154              base64 -d <UUID>.dig | \\
155              openssl pkeyutl -sign -inkey <KEYFILE>.pem \\
156                  -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss \\
157                  -pkeyopt rsa_pss_saltlen:digest \\
158                  -pkeyopt rsa_mgf1_md:sha256 | \\
159              base64 > <UUID>.sig
160
161            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 | \\
166              base64 > <UUID>.sig
167            '''))
168    parser_digest.set_defaults(func=command_digest)
169    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)
177
178    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')
182    parser_stitch.set_defaults(func=command_stitch)
183    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)
192
193    parser_verify = subparsers.add_parser(
194        'verify', prog=parser.prog + ' verify',
195        help='Verify signed TA binary')
196    parser_verify.set_defaults(func=command_verify)
197    arg_add_uuid(parser_verify)
198    arg_add_in(parser_verify)
199    arg_add_key(parser_verify)
200
201    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
207    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
213
214    parsed = parser.parse_args(argv)
215
216    if parsed.command is None:
217        parser.print_help()
218        sys.exit(1)
219
220    # 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)
225
226    return parsed
227
228
229def load_asymmetric_key(arg_key):
230    if arg_key.startswith('arn:'):
231        from sign_helper_kms import _RSAPrivateKeyInKMS
232        key = _RSAPrivateKeyInKMS(arg_key)
233    else:
234        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:
239            data = f.read()
240
241            try:
242                key = load_pem_private_key(data, password=None,
243                                           backend=default_backend())
244            except ValueError:
245                key = load_pem_public_key(data, backend=default_backend())
246
247    return key
248
249
250class BinaryImage:
251    def __init__(self, arg_inf, arg_key):
252        from cryptography.hazmat.primitives import hashes
253
254        # Exactly what inf is holding isn't determined a this stage
255        with open(arg_inf, 'rb') as f:
256            self.inf = f.read()
257
258        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)
263
264        self.chosen_hash = hashes.SHA256()
265        self.digest_len = self.chosen_hash.digest_size
266
267    def __pack_img(self, img_type, sign_algo):
268        import struct
269
270        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):
292        from cryptography.hazmat.primitives.ciphers.aead import AESGCM
293        import struct
294        import os
295
296        self.img = self.inf
297
298        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:]
304
305        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))
309
310        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()
314
315    def set_bootstrap_ta(self, sig_algo, uuid, ta_version):
316        import struct
317
318        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()
323
324    def parse(self):
325        import struct
326
327        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
332
333        if magic != SHDR_MAGIC:
334            raise Exception("Unexpected magic: 0x{:08x}".format(magic))
335
336        if algo_value not in sig_tee_alg.values():
337            raise Exception('Unrecognized algorithm: 0x{:08x}'
338                            .format(algo_value))
339        self.sig_algo = value_to_key(sig_tee_alg, algo_value)
340
341        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))
381        else:
382            raise Exception("Unsupported image type: {}".format(img_type))
383
384    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
498    def decrypt_ta(enc_key):
499        from cryptography.hazmat.primitives.ciphers.aead import AESGCM
500
501        cipher = AESGCM(bytes.fromhex(enc_key))
502        self.img = cipher.decrypt(self.nonce, self.ciphertext, None)
503
504    def __get_padding(self):
505        from cryptography.hazmat.primitives.asymmetric import padding
506
507        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()
512
513        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():
562            raise Exception('Hash digest does not match')
563
564    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
596def 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
633def command_display(args):
634    ta_image = BinaryImage(args.inf, None)
635    ta_image.display()
636
637
638def 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()
647    args.func(args)
648
649
650if __name__ == "__main__":
651    main()
652