binman: add sign option for binman

Introduce proof of concept for binman's new option which provides sign
and replace FIT containers in binary images.

Usage as example:

from:
mkimage -G privateky -r -o sha256,rsa4096 -F fit
binman replace -i flash.bin -f fit.fit fit

to:
binman sign -i flash.bin -k privatekey -a sha256,rsa4096 -f fit.fit fit

and to this one if it's need to be extracted, signed with key and put it
back in image:
binman sign -i flash.bin -k privatekey -a sha256,rsa4096 fit

Signed-off-by: Ivan Mikhaylov <fr0st61te@gmail.com>
This commit is contained in:
Ivan Mikhaylov 2023-03-08 01:13:39 +00:00 committed by Simon Glass
parent 0f40e23fd2
commit 4023dc9c95
5 changed files with 62 additions and 1 deletions

View File

@ -13,6 +13,7 @@
#include <command.h>
#include <console.h>
#include <env.h>
#include <fdtdec.h>
#include <init.h>
#include <net.h>
#include <version_string.h>

View File

@ -176,6 +176,19 @@ controlled by a description in the board device tree.'''
replace_parser.add_argument('paths', type=str, nargs='*',
help='Paths within file to replace (wildcard)')
sign_parser = subparsers.add_parser('sign',
help='Sign entries in image')
sign_parser.add_argument('-a', '--algo', type=str, required=True,
help='Hash algorithm e.g. sha256,rsa4096')
sign_parser.add_argument('-f', '--file', type=str, required=False,
help='Input filename to sign')
sign_parser.add_argument('-i', '--image', type=str, required=True,
help='Image filename to update')
sign_parser.add_argument('-k', '--key', type=str, required=True,
help='Private key file for signing')
sign_parser.add_argument('paths', type=str, nargs='*',
help='Paths within file to sign (wildcard)')
if HAS_TESTS:
test_parser = subparsers.add_parser('test', help='Run tests')
test_parser.add_argument('-P', '--processes', type=int,

View File

@ -448,6 +448,29 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
AfterReplace(image, allow_resize=allow_resize, write_map=write_map)
return image
def SignEntries(image_fname, input_fname, privatekey_fname, algo, entry_paths,
write_map=False):
"""Sign and replace the data from one or more entries from input files
Args:
image_fname: Image filename to process
input_fname: Single input filename to use if replacing one file, None
otherwise
algo: Hashing algorithm
entry_paths: List of entry paths to sign
privatekey_fname: Private key filename
write_map (bool): True to write the map file
"""
image_fname = os.path.abspath(image_fname)
image = Image.FromFile(image_fname)
BeforeReplace(image, allow_resize=True)
for entry_path in entry_paths:
entry = image.FindEntryPath(entry_path)
entry.UpdateSignatures(privatekey_fname, algo, input_fname)
AfterReplace(image, allow_resize=True, write_map=write_map)
def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
"""Prepare the images to be processed and select the device tree
@ -660,7 +683,7 @@ def Binman(args):
tools.set_tool_paths(tool_paths or None)
bintool.Bintool.set_tool_dir(args.tooldir)
if args.cmd in ['ls', 'extract', 'replace', 'tool']:
if args.cmd in ['ls', 'extract', 'replace', 'tool', 'sign']:
try:
tout.init(args.verbosity)
if args.cmd == 'replace':
@ -679,6 +702,9 @@ def Binman(args):
do_compress=not args.compressed,
allow_resize=not args.fix_size, write_map=args.map)
if args.cmd == 'sign':
SignEntries(args.image, args.file, args.key, args.algo, args.paths)
if args.cmd == 'tool':
if args.list:
bintool.Bintool.list_all()

View File

@ -835,3 +835,21 @@ class Entry_fit(Entry_section):
def CheckEntries(self):
pass
def UpdateSignatures(self, privatekey_fname, algo, input_fname):
uniq = self.GetUniqueName()
args = [ '-G', privatekey_fname, '-r', '-o', algo, '-F' ]
if input_fname:
fname = input_fname
else:
fname = tools.get_output_filename('%s.fit' % uniq)
tools.write_file(fname, self.GetData())
args.append(fname)
if self.mkimage.run_cmd(*args) is None:
# Bintool is missing; just use empty data as the output
self.record_missing_bintool(self.mkimage)
return
data = tools.read_file(fname)
self.WriteData(data)

View File

@ -1014,3 +1014,6 @@ class Entry_section(Entry):
for entry in entries.values():
return entry.read_elf_segments()
return None
def UpdateSignatures(self, privatekey_fname, algo, input_fname):
self.Raise('Updating signatures is not supported with this entry type')