Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ESP32] Made a provision to generate esp_secure_cert partition in factory partition script. #29840

Merged
merged 2 commits into from
Nov 9, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 69 additions & 16 deletions scripts/tools/generate_esp32_chip_factory_bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import cryptography.x509
from bitarray import bitarray
from bitarray.util import ba2int
from esp_secure_cert.tlv_format import generate_partition_ds, generate_partition_no_ds, tlv_priv_key_t, tlv_priv_key_type_t

CHIP_TOPDIR = os.path.dirname(os.path.realpath(__file__))[:-len(os.path.join('scripts', 'tools'))]
sys.path.insert(0, os.path.join(CHIP_TOPDIR, 'scripts', 'tools', 'spake2p'))
Expand All @@ -51,6 +52,7 @@
FACTORY_PARTITION_CSV = 'nvs_partition.csv'
FACTORY_PARTITION_BIN = 'factory_partition.bin'
NVS_KEY_PARTITION_BIN = 'nvs_key_partition.bin'
ESP_SECURE_CERT_PARTITION_BIN = 'esp_secure_cert_partititon.bin'

FACTORY_DATA = {
# CommissionableDataProvider
Expand Down Expand Up @@ -315,17 +317,41 @@ def populate_factory_data(args, spake2p_params):
FACTORY_DATA['iteration-count']['value'] = spake2p_params['Iteration Count']
FACTORY_DATA['salt']['value'] = spake2p_params['Salt']
FACTORY_DATA['verifier']['value'] = spake2p_params['Verifier']
if not args.dac_in_secure_cert:
if args.dac_cert:
FACTORY_DATA['dac-cert']['value'] = os.path.abspath(args.dac_cert)
if args.pai_cert:
FACTORY_DATA['pai-cert']['value'] = os.path.abspath(args.pai_cert)
if args.dac_key:
FACTORY_DATA['dac-key']['value'] = os.path.abspath('dac_raw_privkey.bin')
FACTORY_DATA['dac-pub-key']['value'] = os.path.abspath('dac_raw_pubkey.bin')
else:
# esp secure cert partition
secure_cert_partition_file_path = os.path.join(args.output_dir, ESP_SECURE_CERT_PARTITION_BIN)
if args.ds_peripheral:
if args.target != "esp32h2":
logging.error("DS peripheral is only supported for esp32h2 target")
exit(1)
if args.efuse_key_id == -1:
logging.error("--efuse-key-id <value> is required when -ds or --ds-peripheral option is used")
exit(1)
priv_key = tlv_priv_key_t(key_type=tlv_priv_key_type_t.ESP_SECURE_CERT_ECDSA_PERIPHERAL_KEY,
key_path=args.dac_key, key_pass=None)
# priv_key_len is in bits
priv_key.priv_key_len = 256
shripad621git marked this conversation as resolved.
Show resolved Hide resolved
priv_key.efuse_key_id = args.efuse_key_id
generate_partition_ds(priv_key=priv_key, device_cert=args.dac_cert,
ca_cert=args.pai_cert, idf_target=args.target,
op_file=secure_cert_partition_file_path)
else:
priv_key = tlv_priv_key_t(key_type=tlv_priv_key_type_t.ESP_SECURE_CERT_DEFAULT_FORMAT_KEY,
key_path=args.dac_key, key_pass=None)
generate_partition_no_ds(priv_key=priv_key, device_cert=args.dac_cert,
ca_cert=args.pai_cert, idf_target=args.target,
op_file=secure_cert_partition_file_path)

if args.dac_cert:
FACTORY_DATA['dac-cert']['value'] = os.path.abspath(args.dac_cert)
if args.pai_cert:
FACTORY_DATA['pai-cert']['value'] = os.path.abspath(args.pai_cert)
if args.cd:
FACTORY_DATA['cert-dclrn']['value'] = os.path.abspath(args.cd)
if args.dac_key:
FACTORY_DATA['dac-key']['value'] = os.path.abspath('dac_raw_privkey.bin')
FACTORY_DATA['dac-pub-key']['value'] = os.path.abspath('dac_raw_pubkey.bin')

if args.serial_num:
FACTORY_DATA['serial-num']['value'] = args.serial_num
if args.rd_id_uid:
Expand Down Expand Up @@ -486,9 +512,9 @@ def generate_nvs_csv(out_csv_filename):
logging.info('Generated the factory partition csv file : {}'.format(os.path.abspath(out_csv_filename)))


def generate_nvs_bin(encrypt, size, csv_filename, bin_filename):
def generate_nvs_bin(encrypt, size, csv_filename, bin_filename, output_dir):
nvs_args = SimpleNamespace(version=2,
outdir=os.getcwd(),
outdir=output_dir,
input=csv_filename,
output=bin_filename,
size=hex(size))
Expand Down Expand Up @@ -517,7 +543,8 @@ def clean_up():
os.remove(FACTORY_DATA['dac-key']['value'])


def main():
def get_args():

def any_base_int(s): return int(s, 0)

parser = argparse.ArgumentParser(description='Chip Factory NVS binary generator tool')
Expand All @@ -534,6 +561,14 @@ def any_base_int(s): return int(s, 0)
parser.add_argument('--pai-cert', help='The path to the PAI certificate in der format')
parser.add_argument('--cd', help='The path to the certificate declaration der format')

# Options for esp_secure_cert_partition
parser.add_argument('--dac-in-secure-cert', action="store_true",
help='Store DAC in secure cert partition. By default, DAC is stored in nvs factory partition.')
parser.add_argument('-ds', '--ds-peripheral', action="store_true",
help='Use DS Peripheral in generating secure cert partition.')
parser.add_argument('--efuse-key-id', type=int, choices=range(0, 6), default=-1,
help='Provide the efuse key_id which contains/will contain HMAC_KEY, default is 1')

# These will be used by DeviceInstanceInfoProvider
parser.add_argument('--vendor-id', type=any_base_int, help='Vendor id')
parser.add_argument('--vendor-name', help='Vendor name')
Expand All @@ -559,13 +594,20 @@ def any_base_int(s): return int(s, 0)

parser.add_argument('-s', '--size', type=any_base_int, default=0x6000,
help='The size of the partition.bin, default: 0x6000')
parser.add_argument('--target', default='esp32',
help='The platform type of device. eg: one of esp32, esp32c3, etc.')
parser.add_argument('-e', '--encrypt', action='store_true',
help='Encrypt the factory parititon NVS binary')
parser.add_argument('--no-bin', action='store_false', dest='generate_bin',
help='Do not generate the factory partition binary')
parser.add_argument('--output_dir', type=str, default='bin', help='Created image output file path')

parser.set_defaults(generate_bin=True)

args = parser.parse_args()
return parser.parse_args()


def set_up_factory_data(args):
validate_args(args)

if args.passcode is not None:
Expand All @@ -575,18 +617,29 @@ def any_base_int(s): return int(s, 0)

populate_factory_data(args, spake2p_params)

if args.dac_key:
if args.dac_key and not args.dac_in_secure_cert:
gen_raw_ec_keypair_from_der(args.dac_key, FACTORY_DATA['dac-pub-key']['value'], FACTORY_DATA['dac-key']['value'])

generate_nvs_csv(FACTORY_PARTITION_CSV)

def generate_factory_partiton_binary(args):
generate_nvs_csv(FACTORY_PARTITION_CSV)
if args.generate_bin:
generate_nvs_bin(args.encrypt, args.size, FACTORY_PARTITION_CSV, FACTORY_PARTITION_BIN)
generate_nvs_bin(args.encrypt, args.size, FACTORY_PARTITION_CSV, FACTORY_PARTITION_BIN, args.output_dir)
print_flashing_help(args.encrypt, FACTORY_PARTITION_BIN)

clean_up()


def set_up_out_dirs(args):
os.makedirs(args.output_dir, exist_ok=True)


def main():
args = get_args()
set_up_out_dirs(args)
set_up_factory_data(args)
generate_factory_partiton_binary(args)


if __name__ == "__main__":
logging.basicConfig(format='[%(asctime)s] [%(levelname)7s] - %(message)s', level=logging.INFO)
main()
Loading