blob: ea2893495bde66e860b6dfba9305eb5bbd1ccf1d [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)
David Brownd36e91a2017-09-01 09:33:00 -060029 if args.lang == 'c':
30 key.emit_c()
31 elif args.lang == 'rust':
32 key.emit_rust()
33 else:
34 msg = "Unsupported language, valid are: c, or rust"
35 raise argparse.ArgumentTypeError(msg)
David Brown23f91ad2017-05-16 11:38:17 -060036
37def do_sign(args):
David Brown07916c32017-05-31 13:38:31 -060038 if args.rsa_pkcs1_15:
39 keys.sign_rsa_pss = False
David Brown23f91ad2017-05-16 11:38:17 -060040 img = image.Image.load(args.infile, version=args.version,
41 header_size=args.header_size,
David Brown2c21f712017-06-08 10:03:42 -060042 included_header=args.included_header,
David Brown23f91ad2017-05-16 11:38:17 -060043 pad=args.pad)
David Brown0f0c6a82017-06-08 09:26:24 -060044 key = keys.load(args.key) if args.key else None
David Brown23f91ad2017-05-16 11:38:17 -060045 img.sign(key)
46
47 if args.pad:
48 img.pad_to(args.pad, args.align)
49
50 img.save(args.outfile)
51
52subcmds = {
53 'keygen': do_keygen,
54 'getpub': do_getpub,
55 'sign': do_sign, }
56
57def alignment_value(text):
58 value = int(text)
59 if value not in [1, 2, 4, 8]:
60 msg = "{} must be one of 1, 2, 4 or 8".format(value)
61 raise argparse.ArgumentTypeError(msg)
62 return value
63
64def intparse(text):
65 """Parse a command line argument as an integer.
66
67 Accepts 0x and other prefixes to allow other bases to be used."""
68 return int(text, 0)
69
70def args():
71 parser = argparse.ArgumentParser()
72 subs = parser.add_subparsers(help='subcommand help', dest='subcmd')
73
74 keygenp = subs.add_parser('keygen', help='Generate pub/private keypair')
75 keygenp.add_argument('-k', '--key', metavar='filename', required=True)
76 keygenp.add_argument('-t', '--type', metavar='type',
77 choices=['rsa-2048', 'ecdsa-p224', 'ecdsa-p256'],
78 required=True)
79
80 getpub = subs.add_parser('getpub', help='Get public key from keypair')
81 getpub.add_argument('-k', '--key', metavar='filename', required=True)
David Brownd36e91a2017-09-01 09:33:00 -060082 getpub.add_argument('-l', '--lang', metavar='lang', default='c')
David Brown23f91ad2017-05-16 11:38:17 -060083
84 sign = subs.add_parser('sign', help='Sign an image with a private key')
David Brown0f0c6a82017-06-08 09:26:24 -060085 sign.add_argument('-k', '--key', metavar='filename')
David Brown23f91ad2017-05-16 11:38:17 -060086 sign.add_argument("--align", type=alignment_value, required=True)
87 sign.add_argument("-v", "--version", type=version.decode_version, required=True)
88 sign.add_argument("-H", "--header-size", type=intparse, required=True)
David Brown2c21f712017-06-08 10:03:42 -060089 sign.add_argument("--included-header", default=False, action='store_true',
90 help='Image has gap for header')
David Brown23f91ad2017-05-16 11:38:17 -060091 sign.add_argument("--pad", type=intparse,
92 help='Pad image to this many bytes, adding trailer magic')
David Brown07916c32017-05-31 13:38:31 -060093 sign.add_argument("--rsa-pkcs1-15", help='Use old PKCS#1 v1.5 signature algorithm',
94 default=False, action='store_true')
David Brown23f91ad2017-05-16 11:38:17 -060095 sign.add_argument("infile")
96 sign.add_argument("outfile")
97
98 args = parser.parse_args()
99 if args.subcmd is None:
100 print('Must specify a subcommand', file=sys.stderr)
101 sys.exit(1)
102
103 subcmds[args.subcmd](args)
104
105if __name__ == '__main__':
106 args()