blob: 4adb9a4e9bf44261dbed6eefa8d610f18cf44130 [file] [log] [blame]
# 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 binman.entry import EntryArg
from binman.etype.collection import Entry_collection
from dtoc import fdt_util
from u_boot_pylib import tools
class Entry_vblock(Entry_collection):
"""An entry which contains a Chromium OS verified boot block
Properties / Entry arguments:
- content: List of phandles to entries to sign
- 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)
Output files:
- input.<unique_name> - input file passed to futility
- vblock.<unique_name> - output file generated by futility (which is
used as the entry contents)
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):
super().__init__(section, etype, node)
self.futility = None
(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 GetVblock(self, required):
"""Get the contents of this entry
Args:
required: True if the data must be present, False if it is OK to
return None
Returns:
bytes content of the entry, which is the signed vblock for the
provided data
"""
# Join up the data files to be signed
input_data = self.GetContents(required)
if input_data is None:
return None
uniq = self.GetUniqueName()
output_fname = tools.get_output_filename('vblock.%s' % uniq)
input_fname = tools.get_output_filename('input.%s' % uniq)
tools.write_file(input_fname, input_data)
prefix = self.keydir + '/'
stdout = self.futility.sign_firmware(
vblock=output_fname,
keyblock=prefix + self.keyblock,
signprivate=prefix + self.signprivate,
version=f'{self.version:d}',
firmware=input_fname,
kernelkey=prefix + self.kernelkey,
flags=f'{self.preamble_flags}')
if stdout is not None:
data = tools.read_file(output_fname)
else:
# Bintool is missing; just use 4KB of zero data
self.record_missing_bintool(self.futility)
data = tools.get_bytes(0, 4096)
return data
def ObtainContents(self):
data = self.GetVblock(False)
if data is None:
return False
self.SetContents(data)
return True
def ProcessContents(self):
# The blob may have changed due to WriteSymbols()
data = self.GetVblock(True)
return self.ProcessContentsUpdate(data)
def AddBintools(self, btools):
super().AddBintools(btools)
self.futility = self.AddBintool(btools, 'futility')