Jan Kiszka | 4020ce0 | 2023-02-28 19:19:16 +0100 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # SPDX-License-Identifier: GPL-2.0-only |
| 3 | # |
| 4 | # Public key to dtsi converter. |
| 5 | # |
| 6 | # Copyright (c) Siemens AG, 2022 |
| 7 | # |
| 8 | |
| 9 | from argparse import ArgumentParser, FileType |
| 10 | from os.path import basename, splitext |
| 11 | from Cryptodome.PublicKey import RSA |
| 12 | from Cryptodome.Util.number import inverse |
| 13 | |
| 14 | def int_to_bytestr(n, length=None): |
| 15 | if not length: |
| 16 | length = (n.bit_length() + 7) // 8 |
| 17 | byte_array = n.to_bytes(length, 'big') |
| 18 | return ' '.join(['{:02x}'.format(byte) for byte in byte_array]) |
| 19 | |
| 20 | ap = ArgumentParser(description='Public key to dtsi converter') |
| 21 | |
| 22 | ap.add_argument('--hash', '-H', default='sha256', |
| 23 | help='hash to be used with key (default: sha256)') |
| 24 | ap.add_argument('--required-conf', '-c', action='store_true', |
| 25 | help='mark key required for configuration') |
| 26 | ap.add_argument('--required-image', '-i', action='store_true', |
| 27 | help='mark key required for image') |
| 28 | ap.add_argument('--spl', '-s', action='store_true', |
| 29 | help='mark key for usage in SPL') |
| 30 | ap.add_argument('key_file', metavar='KEY_FILE', type=FileType('r'), |
| 31 | help='key file (formats: X.509, PKCS#1, OpenSSH)') |
| 32 | ap.add_argument('dtsi_file', metavar='DTSI_FILE', type=FileType('w'), |
| 33 | help='dtsi output file') |
| 34 | |
| 35 | args = ap.parse_args() |
| 36 | |
| 37 | key_name, _ = splitext(basename(args.key_file.name)) |
| 38 | |
| 39 | key_data = args.key_file.read() |
| 40 | key = RSA.importKey(key_data) |
| 41 | |
| 42 | r_squared = (2**key.size_in_bits())**2 % key.n |
| 43 | n0_inverse = 2**32 - inverse(key.n, 2**32) |
| 44 | |
| 45 | out = args.dtsi_file |
| 46 | out.write('/ {\n') |
| 47 | out.write('\tsignature {\n') |
| 48 | out.write('\t\tkey-{} {{\n'.format(key_name)) |
| 49 | out.write('\t\t\tkey-name-hint = "{}";\n'.format(key_name)) |
| 50 | out.write('\t\t\talgo = "{},rsa{}";\n'.format(args.hash, key.size_in_bits())) |
| 51 | out.write('\t\t\trsa,num-bits = <{}>;\n'.format(key.size_in_bits())) |
| 52 | out.write('\t\t\trsa,modulus = [{}];\n'.format(int_to_bytestr(key.n))) |
| 53 | out.write('\t\t\trsa,exponent = [{}];\n'.format(int_to_bytestr(key.e, 8))) |
| 54 | out.write('\t\t\trsa,r-squared = [{}];\n'.format(int_to_bytestr(r_squared))) |
| 55 | out.write('\t\t\trsa,n0-inverse = <0x{:x}>;\n'.format(n0_inverse)) |
| 56 | if args.required_conf: |
| 57 | out.write('\t\t\trequired = "conf";\n') |
| 58 | elif args.required_image: |
| 59 | out.write('\t\t\trequired = "image";\n') |
| 60 | if args.spl: |
| 61 | out.write('\t\t\tu-boot,dm-spl;\n') |
| 62 | out.write('\t\t};\n') |
| 63 | out.write('\t};\n') |
| 64 | out.write('};\n') |