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
|
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)
|
Entry.WriteMapLine(fd, indent, self._name, self._offset, self._size)
|
||||||
for entry in self._entries.values():
|
for entry in self._entries.values():
|
||||||
entry.WriteMap(fd, indent + 1)
|
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.name = node and (name_prefix + node.name) or 'none'
|
||||||
self.offset = None
|
self.offset = None
|
||||||
self.size = None
|
self.size = None
|
||||||
self.data = ''
|
self.data = None
|
||||||
self.contents_size = 0
|
self.contents_size = 0
|
||||||
self.align = None
|
self.align = None
|
||||||
self.align_size = 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'
|
CROS_EC_RW_DATA = 'ecrw'
|
||||||
GBB_DATA = 'gbbd'
|
GBB_DATA = 'gbbd'
|
||||||
BMPBLK_DATA = 'bmp'
|
BMPBLK_DATA = 'bmp'
|
||||||
|
VBLOCK_DATA = 'vblk'
|
||||||
|
|
||||||
|
|
||||||
class TestFunctional(unittest.TestCase):
|
class TestFunctional(unittest.TestCase):
|
||||||
|
@ -1304,6 +1305,46 @@ class TestFunctional(unittest.TestCase):
|
||||||
self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
|
self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
|
||||||
str(e.exception))
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.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