1#! /usr/bin/env python3
2#
3# -----------------------------------------------------------------------------
4# Copyright (c) 2020-2024, Arm Limited. All rights reserved.
5#
6# SPDX-License-Identifier: BSD-3-Clause
7#
8# -----------------------------------------------------------------------------
9
10import os
11import sys
12import click
13from jinja2 import Environment, FileSystemLoader
14from cryptography.hazmat.primitives.hashes import Hash, SHA256
15
16# Add the cwd to the path so that if there is a version of imgtool in there then
17# it gets used over the system imgtool. Used so that imgtool from upstream
18# mcuboot is preferred over system imgtool
19cwd = os.getcwd()
20sys.path = [cwd] + sys.path
21import imgtool
22import imgtool.main
23
24parser_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))
25sys.path.append(parser_path)
26
27# This works around Python 2 and Python 3 handling character encodings
28# differently. More information about this issue at
29# https://click.palletsprojects.com/en/5.x/python3
30os.environ['LC_ALL'] = 'C.UTF-8'
31os.environ['LANG'] = 'C.UTF-8'
32
33
34def get_key_hash_c_array(key_file):
35    key = imgtool.main.load_key(key_file)
36    digest = Hash(SHA256())
37    digest.update(key.get_public_bytes())
38    return hex_to_c_array(digest.finalize())
39
40
41@click.argument('outfile')
42@click.option('--bl2_rot_priv_key_0', metavar='filename', required=True)
43@click.option('--bl2_rot_priv_key_1', metavar='filename', required=False)
44@click.option('--bl2_rot_priv_key_2', metavar='filename', required=False)
45@click.option('--bl2_rot_priv_key_3', metavar='filename', required=False)
46@click.option('--template_path', metavar='filename', required=True)
47@click.option('--secure_debug_pk', metavar='key', required=False)
48@click.option('--huk', metavar='key', required=False)
49@click.option('--iak', metavar='key', required=False)
50@click.option('--boot_seed', metavar='seed', required=False)
51@click.option('--implementation_id', metavar='id', required=False)
52@click.option('--certification_reference', metavar='reference', default="",
53              required=False)
54@click.option('--verification_service_url', metavar='url', default="",
55              required=False)
56@click.option('--entropy_seed', metavar='seed', required=False)
57@click.command(help='''Creates a .c file with the given keys, using the\n
58               provisioning_data_template.jinja2 template which is located in
59               "template_path" and outputs it to "outfile"''')
60def generate_provisioning_data_c(outfile, bl2_rot_priv_key_0,
61                                 bl2_rot_priv_key_1,
62                                 template_path, bl2_rot_priv_key_2,
63                                 bl2_rot_priv_key_3,
64                                 secure_debug_pk, huk, iak, boot_seed,
65                                 implementation_id,
66                                 certification_reference,
67                                 verification_service_url,
68                                 entropy_seed):
69
70    environment = Environment(loader=FileSystemLoader(template_path))
71    template = environment.get_template("provisioning_data_template.jinja2")
72
73    bl2_rot_pub_key_0_hash = ""
74    if bool(bl2_rot_priv_key_0) is True:
75        bl2_rot_pub_key_0_hash = get_key_hash_c_array(bl2_rot_priv_key_0)
76
77    bl2_rot_pub_key_1_hash = ""
78    if bool(bl2_rot_priv_key_1) is True:
79        bl2_rot_pub_key_1_hash = get_key_hash_c_array(bl2_rot_priv_key_1)
80
81    bl2_rot_pub_key_2_hash = ""
82    if bool(bl2_rot_priv_key_2) is True:
83        bl2_rot_pub_key_2_hash = get_key_hash_c_array(bl2_rot_priv_key_2)
84
85    bl2_rot_pub_key_3_hash = ""
86    if bool(bl2_rot_priv_key_3) is True:
87        bl2_rot_pub_key_3_hash = get_key_hash_c_array(bl2_rot_priv_key_3)
88
89    if bool(huk) is False:
90        huk = hex_to_c_array(os.urandom(32))
91
92    if bool(iak) is False:
93        iak = hex_to_c_array(os.urandom(32))
94
95    if bool(boot_seed) is False:
96        boot_seed = hex_to_c_array(os.urandom(32))
97
98    if bool(implementation_id) is False:
99        implementation_id = hex_to_c_array(os.urandom(32))
100
101    if bool(entropy_seed) is False:
102        entropy_seed = hex_to_c_array(os.urandom(64))
103
104    key_arrays = {
105        "bl2_rotpk_0": bl2_rot_pub_key_0_hash,
106        "bl2_rotpk_1": bl2_rot_pub_key_1_hash,
107        "bl2_rotpk_2": bl2_rot_pub_key_2_hash,
108        "bl2_rotpk_3": bl2_rot_pub_key_3_hash,
109        "secure_debug_pk": secure_debug_pk,
110        "huk": huk,
111        "iak": iak,
112        "iak_len": "32",
113        "boot_seed": boot_seed,
114        "implementation_id": implementation_id,
115        "certification_reference": certification_reference,
116        "verification_service_url": verification_service_url,
117        "entropy_seed": entropy_seed
118    }
119
120    with open(outfile, "w") as F:
121        F.write(template.render(key_arrays))
122
123
124def hex_to_c_array(hex_val):
125    c_array = ""
126    for count, b in enumerate(hex_val):
127        if count % 8 == 0 and count != 0:
128            c_array = c_array + '\n'
129        c_array = c_array + "0x{:02x}, ".format(b)
130
131    return c_array
132
133
134if __name__ == '__main__':
135    generate_provisioning_data_c()
136