blob: 6f0fb4e3390041eda60ec7b5f4bcd2648b1e398d [file] [log] [blame]
David Brown23f91ad2017-05-16 11:38:17 -06001#! /usr/bin/env python3
2
3import argparse
4from imgtool import keys
5from imgtool import image
6from imgtool import version
7import sys
8
9def gen_rsa2048(args):
David Brown4c036152017-06-07 09:10:54 -060010 keys.RSA2048.generate().export_private(args.key)
David Brown23f91ad2017-05-16 11:38:17 -060011def gen_ecdsa_p256(args):
David Brown8ae61c02017-07-27 10:23:02 -060012 keys.ECDSA256P1.generate().export_private(args.key)
David Brown23f91ad2017-05-16 11:38:17 -060013def gen_ecdsa_p224(args):
14 print("TODO: p-224 not yet implemented")
15
16keygens = {
17 'rsa-2048': gen_rsa2048,
18 'ecdsa-p256': gen_ecdsa_p256,
19 'ecdsa-p224': gen_ecdsa_p224, }
20
21def do_keygen(args):
22 if args.type not in keygens:
23 msg = "Unexpected key type: {}".format(args.type)
24 raise argparse.ArgumentTypeError(msg)
25 keygens[args.type](args)
26
27def do_getpub(args):
28 key = keys.load(args.key)
29 key.emit_c()
30
31def do_sign(args):
David Brown07916c32017-05-31 13:38:31 -060032 if args.rsa_pkcs1_15:
33 keys.sign_rsa_pss = False
David Brown23f91ad2017-05-16 11:38:17 -060034 img = image.Image.load(args.infile, version=args.version,
35 header_size=args.header_size,
David Brown2c21f712017-06-08 10:03:42 -060036 included_header=args.included_header,
David Brown23f91ad2017-05-16 11:38:17 -060037 pad=args.pad)
David Brown0f0c6a82017-06-08 09:26:24 -060038 key = keys.load(args.key) if args.key else None
David Brown23f91ad2017-05-16 11:38:17 -060039 img.sign(key)
40
41 if args.pad:
42 img.pad_to(args.pad, args.align)
43
44 img.save(args.outfile)
45
46subcmds = {
47 'keygen': do_keygen,
48 'getpub': do_getpub,
49 'sign': do_sign, }
50
51def alignment_value(text):
52 value = int(text)
53 if value not in [1, 2, 4, 8]:
54 msg = "{} must be one of 1, 2, 4 or 8".format(value)
55 raise argparse.ArgumentTypeError(msg)
56 return value
57
58def intparse(text):
59 """Parse a command line argument as an integer.
60
61 Accepts 0x and other prefixes to allow other bases to be used."""
62 return int(text, 0)
63
64def args():
65 parser = argparse.ArgumentParser()
66 subs = parser.add_subparsers(help='subcommand help', dest='subcmd')
67
68 keygenp = subs.add_parser('keygen', help='Generate pub/private keypair')
69 keygenp.add_argument('-k', '--key', metavar='filename', required=True)
70 keygenp.add_argument('-t', '--type', metavar='type',
71 choices=['rsa-2048', 'ecdsa-p224', 'ecdsa-p256'],
72 required=True)
73
74 getpub = subs.add_parser('getpub', help='Get public key from keypair')
75 getpub.add_argument('-k', '--key', metavar='filename', required=True)
76
77 sign = subs.add_parser('sign', help='Sign an image with a private key')
David Brown0f0c6a82017-06-08 09:26:24 -060078 sign.add_argument('-k', '--key', metavar='filename')
David Brown23f91ad2017-05-16 11:38:17 -060079 sign.add_argument("--align", type=alignment_value, required=True)
80 sign.add_argument("-v", "--version", type=version.decode_version, required=True)
81 sign.add_argument("-H", "--header-size", type=intparse, required=True)
David Brown2c21f712017-06-08 10:03:42 -060082 sign.add_argument("--included-header", default=False, action='store_true',
83 help='Image has gap for header')
David Brown23f91ad2017-05-16 11:38:17 -060084 sign.add_argument("--pad", type=intparse,
85 help='Pad image to this many bytes, adding trailer magic')
David Brown07916c32017-05-31 13:38:31 -060086 sign.add_argument("--rsa-pkcs1-15", help='Use old PKCS#1 v1.5 signature algorithm',
87 default=False, action='store_true')
David Brown23f91ad2017-05-16 11:38:17 -060088 sign.add_argument("infile")
89 sign.add_argument("outfile")
90
91 args = parser.parse_args()
92 if args.subcmd is None:
93 print('Must specify a subcommand', file=sys.stderr)
94 sys.exit(1)
95
96 subcmds[args.subcmd](args)
97
98if __name__ == '__main__':
99 args()