Argparse是 Python 标准库中推荐的命令行解析模块。该模块会自动生成提示信息,且在用户给程序传入非法参数时报错。
刚好最近在看optee的sign_encrypt.py,以它为例介绍python的argparse命令解析模块。
脚本参见:optee_os/scripts/sign_encrypt.py at master · OP-TEE/optee_os · GitHub
#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2015, 2017, 2019, Linaro Limited
#
import sys
import math
sig_tee_alg = {'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256': 0x70414930,
'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256': 0x70004830}
enc_tee_alg = {'TEE_ALG_AES_GCM': 0x40000810}
enc_key_type = {'SHDR_ENC_KEY_DEV_SPECIFIC': 0x0,
'SHDR_ENC_KEY_CLASS_WIDE': 0x1}
TEE_ATTR_RSA_MODULUS = 0xD0000130
TEE_ATTR_RSA_PUBLIC_EXPONENT = 0xD0000230
SHDR_BOOTSTRAP_TA = 1
SHDR_ENCRYPTED_TA = 2
SHDR_SUBKEY = 3
SHDR_MAGIC = 0x4f545348
SHDR_SIZE = 20
SK_HDR_SIZE = 20
EHDR_SIZE = 12
UUID_SIZE = 16
# Use 12 bytes for nonce per recommendation
NONCE_SIZE = 12
TAG_SIZE = 16
def value_to_key(db, val):
for k, v in db.items():
if v == val:
return k
def uuid_v5_sha512(namespace_bytes, name):
from cryptography.hazmat.primitives import hashes
from uuid import UUID
h = hashes.Hash(hashes.SHA512())
h.update(namespace_bytes + bytes(name, 'utf-8'))
digest = h.finalize()
return UUID(bytes=digest[:16], version=5)
def name_img_to_str(name_img):
return name_img.decode().split('\x00', 1)[0]
def uuid_parse(s):
from uuid import UUID
return UUID(s)
def int_parse(str):
return int(str, 0)
def get_args():
import argparse
import textwrap
class OnlyOne(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
a = self.dest + '_assigned'
if getattr(namespace, a, False):
raise argparse.ArgumentError(self, 'Can only be given once')
setattr(namespace, a, True)
setattr(namespace, self.dest, values)
def arg_add_uuid(parser):
parser.add_argument(
'--uuid', required=True, type=uuid_parse,
help='String UUID of the TA')
def arg_add_key(parser):
parser.add_argument(
'--key', required=True, help='''
Name of signing and verification key file (PEM format) or an
Amazon Resource Name (arn:) of an AWS KMS asymmetric key.
At least public key for the commands digest, stitch, and
verify, else a private key''')
def arg_add_enc_key(parser):
parser.add_argument(
'--enc-key', required=False, help='Encryption key string')
def arg_add_enc_key_type(parser):
parser.add_argument(
'--enc-key-type', required=False,
default='SHDR_ENC_KEY_DEV_SPECIFIC',
choices=list(enc_key_type.keys()), help='''
Encryption key type,
Defaults to SHDR_ENC_KEY_DEV_SPECIFIC.''')
def arg_add_ta_version(parser):
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
rollback protection of TA install in the secure database.
Defaults to 0.''')
def arg_add_sig(parser):
parser.add_argument(
'--sig', required=True, dest='sigf',
help='Name of signature input file, defaults to .sig')
def arg_add_dig(parser):
parser.add_argument(
'--dig', required=True, dest='digf',
help='Name of digest output file, defaults to .dig')
def arg_add_in(parser):
parser.add_argument(
'--in', required=False, dest='inf', help='''
Name of application input file, defaults to
.stripped.elf''')
def arg_add_out(parser):
parser.add_argument(
'--out', required=True, dest='outf',
help='Name of application output file, defaults to .ta')
def arg_add_algo(parser):
parser.add_argument(
'--algo', required=False, choices=list(sig_tee_alg.keys()),
default='TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256', help='''
The hash and signature algorithm.
Defaults to TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256.''')
def arg_add_subkey(parser):
parser.add_argument(
'--subkey', action=OnlyOne, help='Name of subkey input file')
def arg_add_name(parser):
parser.add_argument('--name',
help='Input name for subspace of a subkey')
def arg_add_subkey_uuid_in(parser):
parser.add_argument(
'--in', required=True, dest='inf',
help='Name of subkey input file')
def arg_add_max_depth(parser):
parser.add_argument(
'--max-depth', required=False, type=int_parse, help='''
Max depth of subkeys below this subkey''')
def arg_add_name_size(parser):
parser.add_argument(
'--name-size', required=True, type=int_parse, help='''
Size of (unsigned) input name for subspace of a subkey.
Set to 0 to create an identity subkey (a subkey having
the same UUID as the next subkey or TA)''')
def arg_add_subkey_version(parser):
parser.add_argument(
'--subkey-version', required=False, type=int_parse, default=0,
help='Subkey version used for rollback protection')
def arg_add_subkey_in(parser):
parser.add_argument(
'--in', required=True, dest='inf', help='''
Name of PEM file with the public key of the new subkey''')
def arg_add_subkey_out(parser):
parser.add_argument(
'--out', required=True, dest='outf',
help='Name of subkey output file')
def get_outf_default(parsed):
return str(parsed.uuid) + '.ta'
def get_inf_default(parsed):
return str(parsed.uuid) + '.stripped.elf'
def get_sigf_default(parsed):
return str(parsed.uuid) + '.sig'
def get_digf_default(parsed):
return str(parsed.uuid) + '.dig'
def assign_default_value(parsed, attr, func):
if hasattr(parsed, attr) and getattr(parsed, attr) is None:
setattr(parsed, attr, func(parsed))
parser = argparse.ArgumentParser(
description='Sign and encrypt (optional) a Trusted Application ' +
' for OP-TEE.',
usage='%(prog)s ...',
epilog=' -h for detailed help')
subparsers = parser.add_subparsers(
title='valid commands, with possible aliases in ()',
dest='command', metavar='')
parser_sign_enc = subparsers.add_parser(
'sign-enc', prog=parser.prog + ' sign-enc',
help='Generate signed and optionally encrypted loadable TA image file')
parser_sign_enc.set_defaults(func=command_sign_enc)
arg_add_uuid(parser_sign_enc)
arg_add_ta_version(parser_sign_enc)
arg_add_in(parser_sign_enc)
arg_add_out(parser_sign_enc)
arg_add_key(parser_sign_enc)
arg_add_subkey(parser_sign_enc)
arg_add_name(parser_sign_enc)
arg_add_enc_key(parser_sign_enc)
arg_add_enc_key_type(parser_sign_enc)
arg_add_algo(parser_sign_enc)
parser_digest = subparsers.add_parser(
'digest', aliases=['generate-digest'], prog=parser.prog + ' digest',
formatter_class=argparse.RawDescriptionHelpFormatter,
help='Generate loadable TA binary image digest for offline signing',
epilog=textwrap.dedent('''\
example offline signing command using OpenSSL for algorithm
TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:
base64 -d .dig | \\
openssl pkeyutl -sign -inkey .pem \\
-pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss \\
-pkeyopt rsa_pss_saltlen:digest \\
-pkeyopt rsa_mgf1_md:sha256 | \\
base64 > .sig
example offline signing command using OpenSSL for algorithm
TEE_ALG_RSASSA_PKCS1_V1_5_SHA256:
base64 -d .dig | \\
openssl pkeyutl -sign -inkey .pem \\
-pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pkcs1 | \\
base64 > .sig
'''))
parser_digest.set_defaults(func=command_digest)
arg_add_uuid(parser_digest)
arg_add_ta_version(parser_digest)
arg_add_in(parser_digest)
arg_add_key(parser_digest)
arg_add_enc_key(parser_digest)
arg_add_enc_key_type(parser_digest)
arg_add_algo(parser_digest)
arg_add_dig(parser_digest)
parser_stitch = subparsers.add_parser(
'stitch', aliases=['stitch-ta'], prog=parser.prog + ' stich',
help='Generate loadable signed and encrypted TA binary image file' +
' from TA raw image and its signature')
parser_stitch.set_defaults(func=command_stitch)
arg_add_uuid(parser_stitch)
arg_add_ta_version(parser_stitch)
arg_add_in(parser_stitch)
arg_add_key(parser_stitch)
arg_add_out(parser_stitch)
arg_add_enc_key(parser_stitch)
arg_add_enc_key_type(parser_stitch)
arg_add_algo(parser_stitch)
arg_add_sig(parser_stitch)
parser_verify = subparsers.add_parser(
'verify', prog=parser.prog + ' verify',
help='Verify signed TA binary')
parser_verify.set_defaults(func=command_verify)
arg_add_uuid(parser_verify)
arg_add_in(parser_verify)
arg_add_key(parser_verify)
parser_display = subparsers.add_parser(
'display', prog=parser.prog + ' display',
help='Parses and displays a signed TA binary')
parser_display.set_defaults(func=command_display)
arg_add_in(parser_display)
parser_subkey_uuid = subparsers.add_parser(
'subkey-uuid', prog=parser.prog + ' subkey-uuid',
help='calculate the UUID of next TA or subkey')
parser_subkey_uuid.set_defaults(func=command_subkey_uuid)
arg_add_subkey_uuid_in(parser_subkey_uuid)
arg_add_name(parser_subkey_uuid)
parser_sign_subkey = subparsers.add_parser(
'sign-subkey', prog=parser.prog + ' sign-subkey',
help='Sign a subkey')
parser_sign_subkey.set_defaults(func=command_sign_subkey)
arg_add_name(parser_sign_subkey)
arg_add_subkey_in(parser_sign_subkey)
arg_add_uuid(parser_sign_subkey)
arg_add_key(parser_sign_subkey)
arg_add_subkey_out(parser_sign_subkey)
arg_add_max_depth(parser_sign_subkey)
arg_add_name_size(parser_sign_subkey)
arg_add_subkey(parser_sign_subkey)
arg_add_subkey_version(parser_sign_subkey)
arg_add_algo(parser_sign_subkey)
argv = sys.argv[1:]
if (len(argv) > 0 and argv[0][0] == '-' and
argv[0] != '-h' and argv[0] != '--help'):
# The default sub-command is 'sign-enc' so add it to the parser
# if one is missing
argv = ['sign-enc'] + argv
parsed = parser.parse_args(argv)
if parsed.command is None:
parser.print_help()
sys.exit(1)
# Set a few defaults if defined for the current command
assign_default_value(parsed, 'inf', get_inf_default)
assign_default_value(parsed, 'outf', get_outf_default)
assign_default_value(parsed, 'sigf', get_sigf_default)
assign_default_value(parsed, 'digf', get_digf_default)
return parsed
def load_asymmetric_key_img(data):
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import (
load_pem_private_key, load_pem_public_key)
try:
return load_pem_private_key(data, password=None,
backend=default_backend())
except ValueError:
return load_pem_public_key(data, backend=default_backend())
def load_asymmetric_key(arg_key):
if arg_key.startswith('arn:'):
from sign_helper_kms import _RSAPrivateKeyInKMS
return _RSAPrivateKeyInKMS(arg_key)
else:
with open(arg_key, 'rb') as f:
return load_asymmetric_key_img(f.read())
class BinaryImage:
def __init__(self, arg_inf, arg_key):
from cryptography.hazmat.primitives import hashes
# Exactly what inf is holding isn't determined a this stage
if isinstance(arg_inf, str):
with open(arg_inf, 'rb') as f:
self.inf = f.read()
else:
self.inf = arg_inf
if arg_key is None:
self.key = None
else:
if isinstance(arg_key, str):
self.key = load_asymmetric_key(arg_key)
else:
self.key = arg_key
self.sig_size = math.ceil(self.key.key_size / 8)
self.chosen_hash = hashes.SHA256()
self.hash_size = self.chosen_hash.digest_size
def __pack_img(self, img_type, sign_algo):
import struct
self.sig_algo = sign_algo
self.img_type = img_type
self.shdr = struct.pack('= getattr(self, 'previous_max_depth')):
logger.error('Max depth of previous subkey is {} '
.format(self.previous_max_depth) +
'and the next value must be smaller')
sys.exit(1)
def int_to_bytes(x: int) -> bytes:
return x.to_bytes((x.bit_length() + 8) // 8, 'big')
n_bytes = int_to_bytes(subkey_pkey.public_numbers().n)
e_bytes = int_to_bytes(subkey_pkey.public_numbers().e)
attrs_end_offs = 16 + 5 * 4 + 2 * 3 * 4
shdr_subkey = struct.pack(' 0:
# name_size is the previous subkey header
name_img = self.inf[offs:offs + name_size]
print(' next name: "{}"'.format(name_img_to_str(name_img)))
offs += name_size
print('Next header at offset: {} (0x{:x})'
.format(offs, offs))
shdr = self.inf[offs:offs + SHDR_SIZE]
[magic, img_type, img_size, algo_value, hash_size,
sig_size] = struct.unpack(' 0:
sk_image = BinaryImage(sk_image.next_inf, None)
sk_image.parse()
if name is None:
name = ''
self.previous_max_depth = sk_image.max_depth
self.name_img = str.encode(name).ljust(sk_image.name_size, b'\0')
def write(self, outf):
with open(outf, 'wb') as f:
if hasattr(self, 'subkey_img'):
f.write(self.subkey_img)
f.write(self.name_img)
f.write(self.shdr)
f.write(self.img_digest)
f.write(self.sig)
if hasattr(self, 'ta_uuid'):
f.write(self.ta_uuid)
f.write(self.ta_version)
if hasattr(self, 'ehdr'):
f.write(self.ehdr)
f.write(self.nonce)
f.write(self.tag)
f.write(self.ciphertext)
else:
f.write(self.img)
def load_ta_image(args):
ta_image = BinaryImage(args.inf, args.key)
if args.enc_key:
ta_image.encrypt_ta(args.enc_key, args.enc_key_type,
args.algo, args.uuid, args.ta_version)
else:
ta_image.set_bootstrap_ta(args.algo, args.uuid, args.ta_version)
return ta_image
def command_sign_enc(args):
ta_image = load_ta_image(args)
if args.subkey:
ta_image.add_subkey(args.subkey, args.name)
ta_image.sign()
ta_image.write(args.outf)
logger.info('Successfully signed application.')
def command_sign_subkey(args):
image = BinaryImage(args.inf, args.key)
if args.subkey:
image.add_subkey(args.subkey, args.name)
image.set_subkey(args.algo, args.name, args.uuid, args.subkey_version,
args.max_depth, args.name_size)
image.sign()
image.write(args.outf)
logger.info('Successfully signed subkey.')
def command_digest(args):
import base64
ta_image = load_ta_image(args)
with open(args.digf, 'wb+') as digfile:
digfile.write(base64.b64encode(ta_image.img_digest))
def command_stitch(args):
ta_image = load_ta_image(args)
ta_image.add_signature(args.sigf)
ta_image.verify_signature()
ta_image.write(args.outf)
logger.info('Successfully applied signature.')
def command_verify(args):
import uuid
image = BinaryImage(args.inf, args.key)
next_uuid = None
max_depth = -1
while True:
image.parse()
if hasattr(image, 'subkey_hdr'): # Subkey
print('Subkey UUID: {}'.format(uuid.UUID(bytes=image.uuid)))
image.verify_signature()
image.verify_digest()
if next_uuid:
if uuid.UUID(bytes=image.uuid) != next_uuid:
raise Exception('UUID {} does not match {}'
.format(uuid.UUID(bytes=image.uuid),
next_uuid))
if max_depth >= 0:
if image.max_depth < 0 or image.max_depth >= max_depth:
raise Exception('Invalid max_depth {} not less than {}'
.format(image.max_depth, max_depth))
max_depth = image.max_depth
if len(image.next_inf) == 0:
logger.info('Subkey is correctly verified.')
return
if image.name_size > 0:
next_uuid = uuid_v5_sha512(image.uuid,
name_img_to_str(image.name_img))
else:
next_uuid = image.uuid
image = BinaryImage(image.next_inf, image.subkey_key)
else: # TA
print('TA UUID: {}'.format(uuid.UUID(bytes=image.ta_uuid)))
if next_uuid:
if uuid.UUID(bytes=image.ta_uuid) != next_uuid:
raise Exception('UUID {} does not match {}'
.format(uuid.UUID(bytes=image.ta_uuid),
next_uuid))
if hasattr(image, 'ciphertext'):
if args.enc_key is None:
logger.error('--enc_key needed to decrypt TA')
sys.exit(1)
image.decrypt_ta(args.enc_key)
image.verify_signature()
image.verify_digest()
image.verify_uuid(args.uuid)
logger.info('Trusted application is correctly verified.')
return
def command_display(args):
ta_image = BinaryImage(args.inf, None)
ta_image.display()
def command_subkey_uuid(args):
import uuid
sk_image = BinaryImage(args.inf, None)
sk_image.parse()
if not hasattr(sk_image, 'next_inf'):
logger.error('Invalid subkey file')
sys.exit(1)
print('Subkey UUID: {}'.format(uuid.UUID(bytes=sk_image.uuid)))
while len(sk_image.next_inf) > 0:
sk_image = BinaryImage(sk_image.next_inf, None)
sk_image.parse()
print('Subkey UUID: {}'.format(uuid.UUID(bytes=sk_image.uuid)))
if args.name:
if len(args.name) > sk_image.name_size:
logger.error('Length of name ({}) '.format(len(args.name)) +
'is larger than max name size ({})'
.format(sk_image.name_size))
sys.exit(1)
print('Next subkey UUID: {}'
.format(uuid_v5_sha512(sk_image.uuid, args.name)))
else:
print('Next subkey UUID unchanged: {}'
.format(uuid.UUID(bytes=sk_image.uuid)))
def main():
import logging
import os
global logger
logging.basicConfig()
logger = logging.getLogger(os.path.basename(__file__))
args = get_args()
args.func(args)
if __name__ == "__main__":
main()
parser = argparse.ArgumentParser(
description='Sign and encrypt (optional) a Trusted Application ' +
' for OP-TEE.',
usage='%(prog)s ...',
epilog=' -h for detailed help')
ArgumentParser 对象的参数有:
prog -- 程序的名称(默认:sys.argv[0])
usage -- 描述程序用途的字符串(默认值:从添加到解析器的参数生成)
description -- 在参数帮助文档之前显示的文本(默认值:无)。这个参数简要描述这个程序做什么以及怎么做。
epilog -- 在参数帮助文档之后显示的文本(默认值:无)
parents -- 一个 ArgumentParser 对象的列表,它们的参数也应包含在内
formatter_class -- 用于自定义帮助文档输出格式的类
prefix_chars -- 可选参数的前缀字符集合(默认值:’-’)
fromfile_prefix_chars -- 当需要从文件中读取其他参数时,用于标识文件名的前缀字符集合(默认值:None)
argument_default -- 参数的全局默认值(默认值: None)
conflict_handler -- 解决冲突选项的策略(通常是不必要的)
add_help -- 为解析器添加一个 -h/--help 选项(默认值: True)
allow_abbrev -- 如果缩写是无歧义的,则允许缩写长选项 (默认值:True)exit_on_error -- 确定发生错误时 ArgumentParser 是否退出并显示错误信息
添加参数是由add_argument() 方法完成的,它指定 ArgumentParser对象如何获取命令行字符串并将其转换为对象。这些信息将会在 parse_args() 调用时被存储和使用。例如:
def arg_add_uuid(parser):
parser.add_argument(
'--uuid', required=True, type=uuid_parse,
help='String UUID of the TA')
def arg_add_key(parser):
parser.add_argument(
'--key', required=True, help='''
Name of signing and verification key file (PEM format) or an
Amazon Resource Name (arn:) of an AWS KMS asymmetric key.
At least public key for the commands digest, stitch, and
verify, else a private key''')
def arg_add_enc_key(parser):
parser.add_argument(
'--enc-key', required=False, help='Encryption key string')
def arg_add_enc_key_type(parser):
parser.add_argument(
'--enc-key-type', required=False,
default='SHDR_ENC_KEY_DEV_SPECIFIC',
choices=list(enc_key_type.keys()), help='''
Encryption key type,
Defaults to SHDR_ENC_KEY_DEV_SPECIFIC.''')
def arg_add_ta_version(parser):
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
rollback protection of TA install in the secure database.
Defaults to 0.''')
def arg_add_sig(parser):
parser.add_argument(
'--sig', required=True, dest='sigf',
help='Name of signature input file, defaults to .sig')
def arg_add_dig(parser):
parser.add_argument(
'--dig', required=True, dest='digf',
help='Name of digest output file, defaults to .dig')
def arg_add_in(parser):
parser.add_argument(
'--in', required=False, dest='inf', help='''
Name of application input file, defaults to
.stripped.elf''')
def arg_add_out(parser):
parser.add_argument(
'--out', required=True, dest='outf',
help='Name of application output file, defaults to .ta')
def arg_add_algo(parser):
parser.add_argument(
'--algo', required=False, choices=list(sig_tee_alg.keys()),
default='TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256', help='''
The hash and signature algorithm.
Defaults to TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256.''')
def arg_add_subkey(parser):
parser.add_argument(
'--subkey', action=OnlyOne, help='Name of subkey input file')
def arg_add_name(parser):
parser.add_argument('--name',
help='Input name for subspace of a subkey')
def arg_add_subkey_uuid_in(parser):
parser.add_argument(
'--in', required=True, dest='inf',
help='Name of subkey input file')
def arg_add_max_depth(parser):
parser.add_argument(
'--max-depth', required=False, type=int_parse, help='''
Max depth of subkeys below this subkey''')
def arg_add_name_size(parser):
parser.add_argument(
'--name-size', required=True, type=int_parse, help='''
Size of (unsigned) input name for subspace of a subkey.
Set to 0 to create an identity subkey (a subkey having
the same UUID as the next subkey or TA)''')
def arg_add_subkey_version(parser):
parser.add_argument(
'--subkey-version', required=False, type=int_parse, default=0,
help='Subkey version used for rollback protection')
def arg_add_subkey_in(parser):
parser.add_argument(
'--in', required=True, dest='inf', help='''
Name of PEM file with the public key of the new subkey''')
def arg_add_subkey_out(parser):
parser.add_argument(
'--out', required=True, dest='outf',
help='Name of subkey output file')
parse_args() 方法检查命令行,把每个参数转换为适当的类型然后调用相应的操作。
parsed = parser.parse_args(argv)
if parsed.command is None:
parser.print_help()
sys.exit(1)
功能比较多的命令端程序常常将功能分解到不同子命令中。
subparsers = parser.add_subparsers(
title='valid commands, with possible aliases in ()',
dest='command', metavar='')
parser_sign_enc = subparsers.add_parser(
'sign-enc', prog=parser.prog + ' sign-enc',
help='Generate signed and optionally encrypted loadable TA image file')
arg_add_uuid(parser_sign_enc)
arg_add_ta_version(parser_sign_enc)
arg_add_in(parser_sign_enc)
arg_add_out(parser_sign_enc)
arg_add_key(parser_sign_enc)
arg_add_subkey(parser_sign_enc)
arg_add_name(parser_sign_enc)
arg_add_enc_key(parser_sign_enc)
arg_add_enc_key_type(parser_sign_enc)
arg_add_algo(parser_sign_enc)
argparse提供了一个一个方法set_defaults(),可以将子命令绑定特定的函数。
parser_sign_enc.set_defaults(func=command_sign_enc)
综上,sign_encrypt.py脚本有以下8个子命令,对应8个功能点:
sign-enc、digest、stitch、verify、display、subkey_uuid、sign_subkey
即:
$python3 sign_encrypt.py -h
usage: sign_encrypt.py ...
Sign and encrypt (optional) a Trusted Application for OP-TEE.
options:
-h, --help show this help message and exit
valid commands, with possible aliases in ():
sign-enc Generate signed and optionally encrypted loadable TA image file
digest (generate-digest)
Generate loadable TA binary image digest for offline signing
stitch (stitch-ta) Generate loadable signed and encrypted TA binary image file from TA raw image and its signature
verify Verify signed TA binary
display Parses and displays a signed TA binary
subkey-uuid calculate the UUID of next TA or subkey
sign-subkey Sign a subkey
-h for detailed help
Argparse 教程 — Python 3.11.4 文档