mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-09-08 05:43:21 +09:00
![Alexandru Gagniuc](/assets/img/avatar_default.png)
Originally, the ECDSA code path used 'keydir' as the key filename. mkimage has since been updated to include a new 'keyfile' argument. Use the new argument for passing in the key. Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org>
112 lines
3.8 KiB
Python
112 lines
3.8 KiB
Python
# SPDX-License-Identifier: GPL-2.0+
|
|
#
|
|
# Copyright (c) 2020,2021 Alexandru Gagniuc <mr.nuke.me@gmail.com>
|
|
|
|
"""
|
|
Test ECDSA signing of FIT images
|
|
|
|
This test uses mkimage to sign an existing FIT image with an ECDSA key. The
|
|
signature is then extracted, and verified against pyCryptodome.
|
|
This test doesn't run the sandbox. It only checks the host tool 'mkimage'
|
|
"""
|
|
|
|
import pytest
|
|
import u_boot_utils as util
|
|
from Cryptodome.Hash import SHA256
|
|
from Cryptodome.PublicKey import ECC
|
|
from Cryptodome.Signature import DSS
|
|
|
|
class SignableFitImage(object):
|
|
""" Helper to manipulate a FIT image on disk """
|
|
def __init__(self, cons, file_name):
|
|
self.fit = file_name
|
|
self.cons = cons
|
|
self.signable_nodes = set()
|
|
|
|
def __fdt_list(self, path):
|
|
return util.run_and_log(self.cons, f'fdtget -l {self.fit} {path}')
|
|
|
|
def __fdt_set(self, node, **prop_value):
|
|
for prop, value in prop_value.items():
|
|
util.run_and_log(self.cons, f'fdtput -ts {self.fit} {node} {prop} {value}')
|
|
|
|
def __fdt_get_binary(self, node, prop):
|
|
numbers = util.run_and_log(self.cons, f'fdtget -tbi {self.fit} {node} {prop}')
|
|
|
|
bignum = bytearray()
|
|
for little_num in numbers.split():
|
|
bignum.append(int(little_num))
|
|
|
|
return bignum
|
|
|
|
def find_signable_image_nodes(self):
|
|
for node in self.__fdt_list('/images').split():
|
|
image = f'/images/{node}'
|
|
if 'signature' in self.__fdt_list(image):
|
|
self.signable_nodes.add(image)
|
|
|
|
return self.signable_nodes
|
|
|
|
def change_signature_algo_to_ecdsa(self):
|
|
for image in self.signable_nodes:
|
|
self.__fdt_set(f'{image}/signature', algo='sha256,ecdsa256')
|
|
|
|
def sign(self, mkimage, key_file):
|
|
util.run_and_log(self.cons, [mkimage, '-F', self.fit, f'-G{key_file}'])
|
|
|
|
def check_signatures(self, key):
|
|
for image in self.signable_nodes:
|
|
raw_sig = self.__fdt_get_binary(f'{image}/signature', 'value')
|
|
raw_bin = self.__fdt_get_binary(image, 'data')
|
|
|
|
sha = SHA256.new(raw_bin)
|
|
verifier = DSS.new(key, 'fips-186-3')
|
|
verifier.verify(sha, bytes(raw_sig))
|
|
|
|
|
|
@pytest.mark.buildconfigspec('fit_signature')
|
|
@pytest.mark.requiredtool('dtc')
|
|
@pytest.mark.requiredtool('fdtget')
|
|
@pytest.mark.requiredtool('fdtput')
|
|
def test_fit_ecdsa(u_boot_console):
|
|
""" Test that signatures generated by mkimage are legible. """
|
|
def generate_ecdsa_key():
|
|
return ECC.generate(curve='prime256v1')
|
|
|
|
def assemble_fit_image(dest_fit, its, destdir):
|
|
dtc_args = f'-I dts -O dtb -i {destdir}'
|
|
util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f', its, dest_fit])
|
|
|
|
def dtc(dts):
|
|
dtb = dts.replace('.dts', '.dtb')
|
|
util.run_and_log(cons, f'dtc {datadir}/{dts} -O dtb -o {tempdir}/{dtb}')
|
|
|
|
cons = u_boot_console
|
|
mkimage = cons.config.build_dir + '/tools/mkimage'
|
|
datadir = cons.config.source_dir + '/test/py/tests/vboot/'
|
|
tempdir = cons.config.result_dir
|
|
key_file = f'{tempdir}/ecdsa-test-key.pem'
|
|
fit_file = f'{tempdir}/test.fit'
|
|
dtc('sandbox-kernel.dts')
|
|
|
|
key = generate_ecdsa_key()
|
|
|
|
# Create a fake kernel image -- zeroes will do just fine
|
|
with open(f'{tempdir}/test-kernel.bin', 'w') as fd:
|
|
fd.write(500 * chr(0))
|
|
|
|
# invocations of mkimage expect to read the key from disk
|
|
with open(key_file, 'w') as f:
|
|
f.write(key.export_key(format='PEM'))
|
|
|
|
assemble_fit_image(fit_file, f'{datadir}/sign-images-sha256.its', tempdir)
|
|
|
|
fit = SignableFitImage(cons, fit_file)
|
|
nodes = fit.find_signable_image_nodes()
|
|
if len(nodes) == 0:
|
|
raise ValueError('FIT image has no "/image" nodes with "signature"')
|
|
|
|
fit.change_signature_algo_to_ecdsa()
|
|
fit.sign(mkimage, key_file)
|
|
fit.check_signatures(key)
|