Rouven Czerwinski | bbaeed4 | 2019-08-07 20:07:00 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 2 | # SPDX-License-Identifier: BSD-2-Clause |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 3 | # |
| 4 | # Copyright (c) 2015, 2017, 2019, Linaro Limited |
| 5 | # |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 6 | |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 7 | import sys |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 8 | import math |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 9 | |
Jerome Forissier | 4a47792 | 2018-11-14 11:02:49 +0100 | [diff] [blame] | 10 | |
Mingyuan Xiang | cf3d6ac | 2020-09-17 19:01:02 +0800 | [diff] [blame] | 11 | algo = {'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256': 0x70414930, |
| 12 | 'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256': 0x70004830} |
| 13 | |
Donald Chan | c45a84b | 2022-01-01 22:32:45 +0000 | [diff] [blame] | 14 | enc_key_type = {'SHDR_ENC_KEY_DEV_SPECIFIC': 0x0, |
| 15 | 'SHDR_ENC_KEY_CLASS_WIDE': 0x1} |
| 16 | |
Donald Chan | a797f20 | 2022-01-10 19:31:13 +0000 | [diff] [blame] | 17 | SHDR_BOOTSTRAP_TA = 1 |
| 18 | SHDR_ENCRYPTED_TA = 2 |
| 19 | SHDR_MAGIC = 0x4f545348 |
| 20 | SHDR_SIZE = 20 |
| 21 | |
Mingyuan Xiang | cf3d6ac | 2020-09-17 19:01:02 +0800 | [diff] [blame] | 22 | |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 23 | def uuid_parse(s): |
| 24 | from uuid import UUID |
| 25 | return UUID(s) |
| 26 | |
| 27 | |
| 28 | def int_parse(str): |
| 29 | return int(str, 0) |
| 30 | |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 31 | |
Jens Wiklander | 5e15300 | 2022-10-06 11:43:54 +0200 | [diff] [blame] | 32 | def get_args(): |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 33 | def arg_add_uuid(parser): |
| 34 | parser.add_argument( |
| 35 | '--uuid', required=True, type=uuid_parse, |
| 36 | help='String UUID of the TA') |
| 37 | |
| 38 | def arg_add_key(parser): |
| 39 | parser.add_argument( |
| 40 | '--key', required=True, help=''' |
| 41 | Name of signing and verification key file (PEM format) or an |
| 42 | Amazon Resource Name (arn:) of an AWS KMS asymmetric key. |
| 43 | At least public key for the commands digest, stitch, and |
| 44 | verify, else a private key''') |
| 45 | |
| 46 | def arg_add_enc_key(parser): |
| 47 | parser.add_argument( |
| 48 | '--enc-key', required=False, help='Encryption key string') |
| 49 | |
| 50 | def arg_add_enc_key_type(parser): |
| 51 | parser.add_argument( |
| 52 | '--enc-key-type', required=False, |
| 53 | default='SHDR_ENC_KEY_DEV_SPECIFIC', |
| 54 | choices=list(enc_key_type.keys()), help=''' |
| 55 | Encryption key type, |
| 56 | Defaults to SHDR_ENC_KEY_DEV_SPECIFIC.''') |
| 57 | |
| 58 | def arg_add_ta_version(parser): |
| 59 | parser.add_argument( |
| 60 | '--ta-version', required=False, type=int_parse, default=0, help=''' |
| 61 | TA version stored as a 32-bit unsigned integer and used for |
| 62 | rollback protection of TA install in the secure database. |
| 63 | Defaults to 0.''') |
| 64 | |
| 65 | def arg_add_sig(parser): |
| 66 | parser.add_argument( |
| 67 | '--sig', required=True, dest='sigf', |
| 68 | help='Name of signature input file, defaults to <UUID>.sig') |
| 69 | |
| 70 | def arg_add_dig(parser): |
| 71 | parser.add_argument( |
| 72 | '--dig', required=True, dest='digf', |
| 73 | help='Name of digest output file, defaults to <UUID>.dig') |
| 74 | |
| 75 | def arg_add_in(parser): |
| 76 | parser.add_argument( |
| 77 | '--in', required=False, dest='inf', help=''' |
| 78 | Name of application input file, defaults to |
| 79 | <UUID>.stripped.elf''') |
| 80 | |
| 81 | def arg_add_out(parser): |
| 82 | parser.add_argument( |
| 83 | '--out', required=True, dest='outf', |
| 84 | help='Name of application output file, defaults to <UUID>.ta') |
| 85 | |
| 86 | def arg_add_algo(parser): |
| 87 | parser.add_argument( |
| 88 | '--algo', required=False, choices=list(algo.keys()), |
| 89 | default='TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256', help=''' |
| 90 | The hash and signature algorithm. |
| 91 | Defaults to TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256.''') |
| 92 | |
| 93 | def get_outf_default(parsed): |
| 94 | return str(parsed.uuid) + '.ta' |
| 95 | |
| 96 | def get_inf_default(parsed): |
| 97 | return str(parsed.uuid) + '.stripped.elf' |
| 98 | |
| 99 | def get_sigf_default(parsed): |
| 100 | return str(parsed.uuid) + '.sig' |
| 101 | |
| 102 | def get_digf_default(parsed): |
| 103 | return str(parsed.uuid) + '.dig' |
| 104 | |
| 105 | def assign_default_value(parsed, attr, func): |
| 106 | if hasattr(parsed, attr) and getattr(parsed, attr) is None: |
| 107 | setattr(parsed, attr, func(parsed)) |
| 108 | |
| 109 | import argparse |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 110 | import textwrap |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 111 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 112 | parser = argparse.ArgumentParser( |
| 113 | description='Sign and encrypt (optional) a Trusted Application ' + |
| 114 | ' for OP-TEE.', |
| 115 | usage='%(prog)s <command> ...', |
| 116 | epilog='<command> -h for detailed help') |
| 117 | subparsers = parser.add_subparsers( |
| 118 | title='valid commands, with possible aliases in ()', |
| 119 | dest='command', metavar='') |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 120 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 121 | parser_sign_enc = subparsers.add_parser( |
| 122 | 'sign-enc', prog=parser.prog + ' sign-enc', |
| 123 | help='Generate signed and optionally encrypted loadable TA image file') |
| 124 | arg_add_uuid(parser_sign_enc) |
| 125 | arg_add_ta_version(parser_sign_enc) |
| 126 | arg_add_in(parser_sign_enc) |
| 127 | arg_add_out(parser_sign_enc) |
| 128 | arg_add_key(parser_sign_enc) |
| 129 | arg_add_enc_key(parser_sign_enc) |
| 130 | arg_add_enc_key_type(parser_sign_enc) |
| 131 | arg_add_algo(parser_sign_enc) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 132 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 133 | parser_digest = subparsers.add_parser( |
| 134 | 'digest', aliases=['generate-digest'], prog=parser.prog + ' digest', |
| 135 | formatter_class=argparse.RawDescriptionHelpFormatter, |
| 136 | help='Generate loadable TA binary image digest for offline signing', |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 137 | epilog=textwrap.dedent('''\ |
Mingyuan Xiang | cf3d6ac | 2020-09-17 19:01:02 +0800 | [diff] [blame] | 138 | example offline signing command using OpenSSL for algorithm |
| 139 | TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256: |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 140 | base64 -d <UUID>.dig | \\ |
| 141 | openssl pkeyutl -sign -inkey <KEYFILE>.pem \\ |
Mingyuan Xiang | cf3d6ac | 2020-09-17 19:01:02 +0800 | [diff] [blame] | 142 | -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss \\ |
| 143 | -pkeyopt rsa_pss_saltlen:digest \\ |
| 144 | -pkeyopt rsa_mgf1_md:sha256 | \\ |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 145 | base64 > <UUID>.sig |
| 146 | |
Mingyuan Xiang | cf3d6ac | 2020-09-17 19:01:02 +0800 | [diff] [blame] | 147 | example offline signing command using OpenSSL for algorithm |
| 148 | TEE_ALG_RSASSA_PKCS1_V1_5_SHA256: |
| 149 | base64 -d <UUID>.dig | \\ |
| 150 | openssl pkeyutl -sign -inkey <KEYFILE>.pem \\ |
| 151 | -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pkcs1 | \\ |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 152 | base64 > <UUID>.sig |
| 153 | ''')) |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 154 | arg_add_uuid(parser_digest) |
| 155 | arg_add_ta_version(parser_digest) |
| 156 | arg_add_in(parser_digest) |
| 157 | arg_add_key(parser_digest) |
| 158 | arg_add_enc_key(parser_digest) |
| 159 | arg_add_enc_key_type(parser_digest) |
| 160 | arg_add_algo(parser_digest) |
| 161 | arg_add_dig(parser_digest) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 162 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 163 | parser_stitch = subparsers.add_parser( |
| 164 | 'stitch', aliases=['stitch-ta'], prog=parser.prog + ' stich', |
| 165 | help='Generate loadable signed and encrypted TA binary image file' + |
| 166 | ' from TA raw image and its signature') |
| 167 | arg_add_uuid(parser_stitch) |
| 168 | arg_add_ta_version(parser_stitch) |
| 169 | arg_add_in(parser_stitch) |
| 170 | arg_add_key(parser_stitch) |
| 171 | arg_add_out(parser_stitch) |
| 172 | arg_add_enc_key(parser_stitch) |
| 173 | arg_add_enc_key_type(parser_stitch) |
| 174 | arg_add_algo(parser_stitch) |
| 175 | arg_add_sig(parser_stitch) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 176 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 177 | parser_verify = subparsers.add_parser( |
| 178 | 'verify', prog=parser.prog + ' verify', |
| 179 | help='Verify signed TA binary') |
| 180 | arg_add_uuid(parser_verify) |
| 181 | arg_add_in(parser_verify) |
| 182 | arg_add_key(parser_verify) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 183 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 184 | argv = sys.argv[1:] |
| 185 | if (len(argv) > 0 and argv[0][0] == '-' and |
| 186 | argv[0] != '-h' and argv[0] != '--help'): |
| 187 | # The default sub-command is 'sign-enc' so add it to the parser |
| 188 | # if one is missing |
| 189 | argv = ['sign-enc'] + argv |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 190 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 191 | parsed = parser.parse_args(argv) |
| 192 | |
| 193 | if parsed.command is None: |
| 194 | parser.print_help() |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 195 | sys.exit(1) |
| 196 | |
Jens Wiklander | f182afc | 2022-10-04 10:19:27 +0200 | [diff] [blame^] | 197 | # Set a few defaults if defined for the current command |
| 198 | assign_default_value(parsed, 'inf', get_inf_default) |
| 199 | assign_default_value(parsed, 'outf', get_outf_default) |
| 200 | assign_default_value(parsed, 'sigf', get_sigf_default) |
| 201 | assign_default_value(parsed, 'digf', get_digf_default) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 202 | |
| 203 | return parsed |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 204 | |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 205 | |
| 206 | def main(): |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 207 | from cryptography import exceptions |
| 208 | from cryptography.hazmat.backends import default_backend |
| 209 | from cryptography.hazmat.primitives import serialization |
| 210 | from cryptography.hazmat.primitives import hashes |
| 211 | from cryptography.hazmat.primitives.asymmetric import padding |
| 212 | from cryptography.hazmat.primitives.asymmetric import rsa |
| 213 | from cryptography.hazmat.primitives.asymmetric import utils |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 214 | import base64 |
| 215 | import logging |
| 216 | import os |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 217 | import struct |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 218 | |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 219 | logging.basicConfig() |
Jens Wiklander | 5e15300 | 2022-10-06 11:43:54 +0200 | [diff] [blame] | 220 | global logger |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 221 | logger = logging.getLogger(os.path.basename(__file__)) |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 222 | |
Jens Wiklander | 5e15300 | 2022-10-06 11:43:54 +0200 | [diff] [blame] | 223 | args = get_args() |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 224 | |
Donald Chan | 05c007f | 2022-01-05 17:54:00 +0000 | [diff] [blame] | 225 | if args.key.startswith('arn:'): |
| 226 | from sign_helper_kms import _RSAPrivateKeyInKMS |
| 227 | key = _RSAPrivateKeyInKMS(args.key) |
| 228 | else: |
| 229 | with open(args.key, 'rb') as f: |
| 230 | data = f.read() |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 231 | |
Donald Chan | 05c007f | 2022-01-05 17:54:00 +0000 | [diff] [blame] | 232 | try: |
| 233 | key = serialization.load_pem_private_key( |
| 234 | data, |
| 235 | password=None, |
| 236 | backend=default_backend()) |
| 237 | except ValueError: |
| 238 | key = serialization.load_pem_public_key( |
| 239 | data, |
| 240 | backend=default_backend()) |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 241 | |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 242 | with open(args.inf, 'rb') as f: |
| 243 | img = f.read() |
| 244 | |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 245 | chosen_hash = hashes.SHA256() |
| 246 | h = hashes.Hash(chosen_hash, default_backend()) |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 247 | |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 248 | digest_len = chosen_hash.digest_size |
| 249 | sig_len = math.ceil(key.key_size / 8) |
Volodymyr Babchuk | 90ad245 | 2019-08-21 21:00:32 +0300 | [diff] [blame] | 250 | |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 251 | img_size = len(img) |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 252 | |
Etienne Carriere | 4784462 | 2019-08-12 11:33:24 +0200 | [diff] [blame] | 253 | hdr_version = args.ta_version # struct shdr_bootstrap_ta::ta_version |
| 254 | |
Donald Chan | a797f20 | 2022-01-10 19:31:13 +0000 | [diff] [blame] | 255 | magic = SHDR_MAGIC |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 256 | if args.enc_key: |
Donald Chan | a797f20 | 2022-01-10 19:31:13 +0000 | [diff] [blame] | 257 | img_type = SHDR_ENCRYPTED_TA |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 258 | else: |
Donald Chan | a797f20 | 2022-01-10 19:31:13 +0000 | [diff] [blame] | 259 | img_type = SHDR_BOOTSTRAP_TA |
Etienne Carriere | 4784462 | 2019-08-12 11:33:24 +0200 | [diff] [blame] | 260 | |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 261 | shdr = struct.pack('<IIIIHH', |
Mingyuan Xiang | cf3d6ac | 2020-09-17 19:01:02 +0800 | [diff] [blame] | 262 | magic, img_type, img_size, algo[args.algo], |
| 263 | digest_len, sig_len) |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 264 | shdr_uuid = args.uuid.bytes |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 265 | shdr_version = struct.pack('<I', hdr_version) |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 266 | |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 267 | if args.enc_key: |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 268 | from cryptography.hazmat.primitives.ciphers.aead import AESGCM |
| 269 | cipher = AESGCM(bytes.fromhex(args.enc_key)) |
| 270 | # Use 12 bytes for nonce per recommendation |
| 271 | nonce = os.urandom(12) |
| 272 | out = cipher.encrypt(nonce, img, None) |
| 273 | ciphertext = out[:-16] |
| 274 | # Authentication Tag is always the last 16 bytes |
| 275 | tag = out[-16:] |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 276 | |
Donald Chan | c45a84b | 2022-01-01 22:32:45 +0000 | [diff] [blame] | 277 | enc_algo = 0x40000810 # TEE_ALG_AES_GCM |
| 278 | flags = enc_key_type[args.enc_key_type] |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 279 | ehdr = struct.pack('<IIHH', |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 280 | enc_algo, flags, len(nonce), len(tag)) |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 281 | |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 282 | h.update(shdr) |
| 283 | h.update(shdr_uuid) |
| 284 | h.update(shdr_version) |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 285 | if args.enc_key: |
| 286 | h.update(ehdr) |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 287 | h.update(nonce) |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 288 | h.update(tag) |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 289 | h.update(img) |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 290 | img_digest = h.finalize() |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 291 | |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 292 | def write_image_with_signature(sig): |
| 293 | with open(args.outf, 'wb') as f: |
| 294 | f.write(shdr) |
| 295 | f.write(img_digest) |
| 296 | f.write(sig) |
| 297 | f.write(shdr_uuid) |
| 298 | f.write(shdr_version) |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 299 | if args.enc_key: |
| 300 | f.write(ehdr) |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 301 | f.write(nonce) |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 302 | f.write(tag) |
| 303 | f.write(ciphertext) |
| 304 | else: |
| 305 | f.write(img) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 306 | |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 307 | def sign_encrypt_ta(): |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 308 | if not isinstance(key, rsa.RSAPrivateKey): |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 309 | logger.error('Provided key cannot be used for signing, ' + |
| 310 | 'please use offline-signing mode.') |
Markus S. Wamser | 6ff2e3f | 2019-08-02 14:48:46 +0200 | [diff] [blame] | 311 | sys.exit(1) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 312 | else: |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 313 | if args.algo == 'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256': |
| 314 | sig = key.sign( |
| 315 | img_digest, |
| 316 | padding.PSS( |
| 317 | mgf=padding.MGF1(chosen_hash), |
| 318 | salt_length=digest_len |
| 319 | ), |
| 320 | utils.Prehashed(chosen_hash) |
| 321 | ) |
| 322 | elif args.algo == 'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256': |
| 323 | sig = key.sign( |
| 324 | img_digest, |
| 325 | padding.PKCS1v15(), |
| 326 | utils.Prehashed(chosen_hash) |
| 327 | ) |
| 328 | |
Volodymyr Babchuk | 90ad245 | 2019-08-21 21:00:32 +0300 | [diff] [blame] | 329 | if len(sig) != sig_len: |
| 330 | raise Exception(("Actual signature length is not equal to ", |
| 331 | "the computed one: {} != {}"). |
| 332 | format(len(sig), sig_len)) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 333 | write_image_with_signature(sig) |
| 334 | logger.info('Successfully signed application.') |
| 335 | |
| 336 | def generate_digest(): |
| 337 | with open(args.digf, 'wb+') as digfile: |
| 338 | digfile.write(base64.b64encode(img_digest)) |
| 339 | |
| 340 | def stitch_ta(): |
| 341 | try: |
| 342 | with open(args.sigf, 'r') as sigfile: |
| 343 | sig = base64.b64decode(sigfile.read()) |
| 344 | except IOError: |
Markus S. Wamser | 6ff2e3f | 2019-08-02 14:48:46 +0200 | [diff] [blame] | 345 | if not os.path.exists(args.digf): |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 346 | generate_digest() |
| 347 | logger.error('No signature file found. Please sign\n %s\n' + |
| 348 | 'offline and place the signature at \n %s\n' + |
| 349 | 'or pass a different location ' + |
| 350 | 'using the --sig argument.\n', |
| 351 | args.digf, args.sigf) |
Markus S. Wamser | 6ff2e3f | 2019-08-02 14:48:46 +0200 | [diff] [blame] | 352 | sys.exit(1) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 353 | else: |
Mingyuan Xiang | cf3d6ac | 2020-09-17 19:01:02 +0800 | [diff] [blame] | 354 | try: |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 355 | if args.algo == 'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256': |
| 356 | key.verify( |
| 357 | sig, |
| 358 | img_digest, |
| 359 | padding.PSS( |
| 360 | mgf=padding.MGF1(chosen_hash), |
| 361 | salt_length=digest_len |
| 362 | ), |
| 363 | utils.Prehashed(chosen_hash) |
| 364 | ) |
| 365 | elif args.algo == 'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256': |
| 366 | key.verify( |
| 367 | sig, |
| 368 | img_digest, |
| 369 | padding.PKCS1v15(), |
| 370 | utils.Prehashed(chosen_hash) |
| 371 | ) |
| 372 | except exceptions.InvalidSignature: |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 373 | logger.error('Verification failed, ignoring given signature.') |
Markus S. Wamser | 6ff2e3f | 2019-08-02 14:48:46 +0200 | [diff] [blame] | 374 | sys.exit(1) |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 375 | |
Donald Chan | 169eac1 | 2021-10-24 14:22:54 -0700 | [diff] [blame] | 376 | write_image_with_signature(sig) |
| 377 | logger.info('Successfully applied signature.') |
| 378 | |
Donald Chan | 51eee1e | 2022-01-11 18:54:25 +0000 | [diff] [blame] | 379 | def verify_ta(): |
| 380 | # Extract header |
| 381 | [magic, |
| 382 | img_type, |
| 383 | img_size, |
| 384 | algo_value, |
| 385 | digest_len, |
| 386 | sig_len] = struct.unpack('<IIIIHH', img[:SHDR_SIZE]) |
| 387 | |
| 388 | # Extract digest and signature |
| 389 | start, end = SHDR_SIZE, SHDR_SIZE + digest_len |
| 390 | digest = img[start:end] |
| 391 | |
| 392 | start, end = end, SHDR_SIZE + digest_len + sig_len |
| 393 | signature = img[start:end] |
| 394 | |
| 395 | # Extract UUID and TA version |
| 396 | start, end = end, end + 16 + 4 |
| 397 | [uuid, ta_version] = struct.unpack('<16sI', img[start:end]) |
| 398 | |
| 399 | if magic != SHDR_MAGIC: |
| 400 | raise Exception("Unexpected magic: 0x{:08x}".format(magic)) |
| 401 | |
| 402 | if img_type != SHDR_BOOTSTRAP_TA: |
| 403 | raise Exception("Unsupported image type: {}".format(img_type)) |
| 404 | |
| 405 | if algo_value not in algo.values(): |
| 406 | raise Exception('Unrecognized algorithm: 0x{:08x}' |
| 407 | .format(algo_value)) |
| 408 | |
| 409 | # Verify signature against hash digest |
| 410 | if algo_value == 0x70414930: |
| 411 | key.verify( |
| 412 | signature, |
| 413 | digest, |
| 414 | padding.PSS( |
| 415 | mgf=padding.MGF1(chosen_hash), |
| 416 | salt_length=digest_len |
| 417 | ), |
| 418 | utils.Prehashed(chosen_hash) |
| 419 | ) |
| 420 | else: |
| 421 | key.verify( |
| 422 | signature, |
| 423 | digest, |
| 424 | padding.PKCS1v15(), |
| 425 | utils.Prehashed(chosen_hash) |
| 426 | ) |
| 427 | |
| 428 | h = hashes.Hash(chosen_hash, default_backend()) |
| 429 | |
| 430 | # sizeof(struct shdr) |
| 431 | h.update(img[:SHDR_SIZE]) |
| 432 | |
| 433 | # sizeof(struct shdr_bootstrap_ta) |
| 434 | h.update(img[start:end]) |
| 435 | |
| 436 | # raw image |
| 437 | start = end |
| 438 | end += img_size |
| 439 | h.update(img[start:end]) |
| 440 | |
| 441 | if digest != h.finalize(): |
| 442 | raise Exception('Hash digest does not match') |
| 443 | |
| 444 | logger.info('Trusted application is correctly verified.') |
| 445 | |
Markus S. Wamser | 6ff2e3f | 2019-08-02 14:48:46 +0200 | [diff] [blame] | 446 | # dispatch command |
| 447 | { |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 448 | 'sign-enc': sign_encrypt_ta, |
Markus S. Wamser | 1cdd95a | 2019-04-30 12:03:12 +0200 | [diff] [blame] | 449 | 'digest': generate_digest, |
| 450 | 'generate-digest': generate_digest, |
| 451 | 'stitch': stitch_ta, |
Donald Chan | 51eee1e | 2022-01-11 18:54:25 +0000 | [diff] [blame] | 452 | 'stitch-ta': stitch_ta, |
| 453 | 'verify': verify_ta, |
Sumit Garg | 2de17fd | 2019-10-23 12:47:24 +0530 | [diff] [blame] | 454 | }.get(args.command, 'sign_encrypt_ta')() |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 455 | |
Jens Wiklander | bc42074 | 2015-05-05 14:59:15 +0200 | [diff] [blame] | 456 | |
| 457 | if __name__ == "__main__": |
Jens Wiklander | cd5cf43 | 2017-11-28 16:59:15 +0100 | [diff] [blame] | 458 | main() |