mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 02:15:45 +01:00 
			
		
		
		
	Use a different temporary dir for each test, to allow them to run in parallel. Signed-off-by: Simon Glass <sjg@chromium.org>
		
			
				
	
	
		
			114 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			114 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 os
 | |
| 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 = os.path.join(cons.config.result_dir, 'ecdsa')
 | |
|     os.makedirs(tempdir, exist_ok=True)
 | |
|     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)
 |