mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-26 06:30:39 +00:00
binman: Add an entry for a Chromium vblock
This adds support for a Chromium verified boot block, used to sign a read-write section of the image. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
94a7c603b4
commit
24d0d3c30d
9 changed files with 259 additions and 1 deletions
|
@ -496,6 +496,23 @@ complicated. Otherwise it is the same as the u_boot entry.
|
|||
|
||||
|
||||
|
||||
Entry: vblock: An entry which contains a Chromium OS verified boot block
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Properties / Entry arguments:
|
||||
- keydir: Directory containing the public keys to use
|
||||
- keyblock: Name of the key file to use (inside keydir)
|
||||
- signprivate: Name of provide key file to use (inside keydir)
|
||||
- version: Version number of the vblock (typically 1)
|
||||
- kernelkey: Name of the kernel key to use (inside keydir)
|
||||
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
||||
|
||||
Chromium OS signs the read-write firmware and kernel, writing the signature
|
||||
in this block. This allows U-Boot to verify that the next firmware stage
|
||||
and kernel are genuine.
|
||||
|
||||
|
||||
|
||||
Entry: x86-start16: x86 16-bit start-up code for U-Boot
|
||||
-------------------------------------------------------
|
||||
|
||||
|
|
|
@ -381,3 +381,27 @@ class Section(object):
|
|||
Entry.WriteMapLine(fd, indent, self._name, self._offset, self._size)
|
||||
for entry in self._entries.values():
|
||||
entry.WriteMap(fd, indent + 1)
|
||||
|
||||
def GetContentsByPhandle(self, phandle, source_entry):
|
||||
"""Get the data contents of an entry specified by a phandle
|
||||
|
||||
This uses a phandle to look up a node and and find the entry
|
||||
associated with it. Then it returnst he contents of that entry.
|
||||
|
||||
Args:
|
||||
phandle: Phandle to look up (integer)
|
||||
source_entry: Entry containing that phandle (used for error
|
||||
reporting)
|
||||
|
||||
Returns:
|
||||
data from associated entry (as a string), or None if not found
|
||||
"""
|
||||
node = self._node.GetFdt().LookupPhandle(phandle)
|
||||
if not node:
|
||||
source_entry.Raise("Cannot find node for phandle %d" % phandle)
|
||||
for entry in self._entries.values():
|
||||
if entry._node == node:
|
||||
if entry.data is None:
|
||||
return None
|
||||
return entry.data
|
||||
source_entry.Raise("Cannot find entry for node '%s'" % node.name)
|
||||
|
|
|
@ -65,7 +65,7 @@ class Entry(object):
|
|||
self.name = node and (name_prefix + node.name) or 'none'
|
||||
self.offset = None
|
||||
self.size = None
|
||||
self.data = ''
|
||||
self.data = None
|
||||
self.contents_size = 0
|
||||
self.align = None
|
||||
self.align_size = None
|
||||
|
|
74
tools/binman/etype/vblock.py
Normal file
74
tools/binman/etype/vblock.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# Copyright (c) 2018 Google, Inc
|
||||
# Written by Simon Glass <sjg@chromium.org>
|
||||
#
|
||||
|
||||
# Support for a Chromium OS verified boot block, used to sign a read-write
|
||||
# section of the image.
|
||||
|
||||
from collections import OrderedDict
|
||||
import os
|
||||
|
||||
from entry import Entry, EntryArg
|
||||
|
||||
import fdt_util
|
||||
import tools
|
||||
|
||||
class Entry_vblock(Entry):
|
||||
"""An entry which contains a Chromium OS verified boot block
|
||||
|
||||
Properties / Entry arguments:
|
||||
- keydir: Directory containing the public keys to use
|
||||
- keyblock: Name of the key file to use (inside keydir)
|
||||
- signprivate: Name of provide key file to use (inside keydir)
|
||||
- version: Version number of the vblock (typically 1)
|
||||
- kernelkey: Name of the kernel key to use (inside keydir)
|
||||
- preamble-flags: Value of the vboot preamble flags (typically 0)
|
||||
|
||||
Chromium OS signs the read-write firmware and kernel, writing the signature
|
||||
in this block. This allows U-Boot to verify that the next firmware stage
|
||||
and kernel are genuine.
|
||||
"""
|
||||
def __init__(self, section, etype, node):
|
||||
Entry.__init__(self, section, etype, node)
|
||||
self.content = fdt_util.GetPhandleList(self._node, 'content')
|
||||
if not self.content:
|
||||
self.Raise("Vblock must have a 'content' property")
|
||||
(self.keydir, self.keyblock, self.signprivate, self.version,
|
||||
self.kernelkey, self.preamble_flags) = self.GetEntryArgsOrProps([
|
||||
EntryArg('keydir', str),
|
||||
EntryArg('keyblock', str),
|
||||
EntryArg('signprivate', str),
|
||||
EntryArg('version', int),
|
||||
EntryArg('kernelkey', str),
|
||||
EntryArg('preamble-flags', int)])
|
||||
|
||||
def ObtainContents(self):
|
||||
# Join up the data files to be signed
|
||||
input_data = ''
|
||||
for entry_phandle in self.content:
|
||||
data = self.section.GetContentsByPhandle(entry_phandle, self)
|
||||
if data is None:
|
||||
# Data not available yet
|
||||
return False
|
||||
input_data += data
|
||||
|
||||
output_fname = tools.GetOutputFilename('vblock.%s' % self.name)
|
||||
input_fname = tools.GetOutputFilename('input.%s' % self.name)
|
||||
tools.WriteFile(input_fname, input_data)
|
||||
prefix = self.keydir + '/'
|
||||
args = [
|
||||
'vbutil_firmware',
|
||||
'--vblock', output_fname,
|
||||
'--keyblock', prefix + self.keyblock,
|
||||
'--signprivate', prefix + self.signprivate,
|
||||
'--version', '%d' % self.version,
|
||||
'--fv', input_fname,
|
||||
'--kernelkey', prefix + self.kernelkey,
|
||||
'--flags', '%d' % self.preamble_flags,
|
||||
]
|
||||
#out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
|
||||
stdout = tools.Run('futility', *args)
|
||||
#out.Debug(stdout)
|
||||
self.SetContents(tools.ReadFile(output_fname))
|
||||
return True
|
|
@ -49,6 +49,7 @@ TEXT_DATA3 = 'text3'
|
|||
CROS_EC_RW_DATA = 'ecrw'
|
||||
GBB_DATA = 'gbbd'
|
||||
BMPBLK_DATA = 'bmp'
|
||||
VBLOCK_DATA = 'vblk'
|
||||
|
||||
|
||||
class TestFunctional(unittest.TestCase):
|
||||
|
@ -1304,6 +1305,46 @@ class TestFunctional(unittest.TestCase):
|
|||
self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
|
||||
str(e.exception))
|
||||
|
||||
def _HandleVblockCommand(self, pipe_list):
|
||||
"""Fake calls to the futility utility"""
|
||||
if pipe_list[0][0] == 'futility':
|
||||
fname = pipe_list[0][3]
|
||||
with open(fname, 'w') as fd:
|
||||
fd.write(VBLOCK_DATA)
|
||||
return command.CommandResult()
|
||||
|
||||
def testVblock(self):
|
||||
"""Test for the Chromium OS Verified Boot Block"""
|
||||
command.test_result = self._HandleVblockCommand
|
||||
entry_args = {
|
||||
'keydir': 'devkeys',
|
||||
}
|
||||
data, _, _, _ = self._DoReadFileDtb('74_vblock.dts',
|
||||
entry_args=entry_args)
|
||||
expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
|
||||
self.assertEqual(expected, data)
|
||||
|
||||
def testVblockNoContent(self):
|
||||
"""Test we detect a vblock which has no content to sign"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('75_vblock_no_content.dts')
|
||||
self.assertIn("Node '/binman/vblock': Vblock must have a 'content' "
|
||||
'property', str(e.exception))
|
||||
|
||||
def testVblockBadPhandle(self):
|
||||
"""Test that we detect a vblock with an invalid phandle in contents"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('76_vblock_bad_phandle.dts')
|
||||
self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
|
||||
'1000', str(e.exception))
|
||||
|
||||
def testVblockBadEntry(self):
|
||||
"""Test that we detect an entry that points to a non-entry"""
|
||||
with self.assertRaises(ValueError) as e:
|
||||
self._DoReadFile('77_vblock_bad_entry.dts')
|
||||
self.assertIn("Node '/binman/vblock': Cannot find entry for node "
|
||||
"'other'", str(e.exception))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
28
tools/binman/test/74_vblock.dts
Normal file
28
tools/binman/test/74_vblock.dts
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
content = <&u_boot &dtb>;
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
/*
|
||||
* Put this after the vblock so that its contents are not
|
||||
* available when the vblock first tries to obtain its contents
|
||||
*/
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
23
tools/binman/test/75_vblock_no_content.dts
Normal file
23
tools/binman/test/75_vblock_no_content.dts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
24
tools/binman/test/76_vblock_bad_phandle.dts
Normal file
24
tools/binman/test/76_vblock_bad_phandle.dts
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
content = <1000>;
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
};
|
27
tools/binman/test/77_vblock_bad_entry.dts
Normal file
27
tools/binman/test/77_vblock_bad_entry.dts
Normal file
|
@ -0,0 +1,27 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
u_boot: u-boot {
|
||||
};
|
||||
|
||||
vblock {
|
||||
content = <&u_boot &other>;
|
||||
keyblock = "firmware.keyblock";
|
||||
signprivate = "firmware_data_key.vbprivk";
|
||||
version = <1>;
|
||||
kernelkey = "kernel_subkey.vbpubk";
|
||||
preamble-flags = <1>;
|
||||
};
|
||||
|
||||
dtb: u-boot-dtb {
|
||||
};
|
||||
};
|
||||
|
||||
other: other {
|
||||
};
|
||||
};
|
Loading…
Reference in a new issue