1# SPDX-License-Identifier: GPL-2.0+ 2# Copyright (c) 2018 Google, Inc 3# Written by Simon Glass <sjg@chromium.org> 4# 5 6# Support for a Chromium OS verified boot block, used to sign a read-write 7# section of the image. 8 9from collections import OrderedDict 10import os 11 12from binman.entry import EntryArg 13from binman.etype.collection import Entry_collection 14 15from dtoc import fdt_util 16from patman import tools 17 18class Entry_vblock(Entry_collection): 19 """An entry which contains a Chromium OS verified boot block 20 21 Properties / Entry arguments: 22 - content: List of phandles to entries to sign 23 - keydir: Directory containing the public keys to use 24 - keyblock: Name of the key file to use (inside keydir) 25 - signprivate: Name of provide key file to use (inside keydir) 26 - version: Version number of the vblock (typically 1) 27 - kernelkey: Name of the kernel key to use (inside keydir) 28 - preamble-flags: Value of the vboot preamble flags (typically 0) 29 30 Output files: 31 - input.<unique_name> - input file passed to futility 32 - vblock.<unique_name> - output file generated by futility (which is 33 used as the entry contents) 34 35 Chromium OS signs the read-write firmware and kernel, writing the signature 36 in this block. This allows U-Boot to verify that the next firmware stage 37 and kernel are genuine. 38 """ 39 def __init__(self, section, etype, node): 40 super().__init__(section, etype, node) 41 (self.keydir, self.keyblock, self.signprivate, self.version, 42 self.kernelkey, self.preamble_flags) = self.GetEntryArgsOrProps([ 43 EntryArg('keydir', str), 44 EntryArg('keyblock', str), 45 EntryArg('signprivate', str), 46 EntryArg('version', int), 47 EntryArg('kernelkey', str), 48 EntryArg('preamble-flags', int)]) 49 50 def GetVblock(self, required): 51 """Get the contents of this entry 52 53 Args: 54 required: True if the data must be present, False if it is OK to 55 return None 56 57 Returns: 58 bytes content of the entry, which is the signed vblock for the 59 provided data 60 """ 61 # Join up the data files to be signed 62 input_data = self.GetContents(required) 63 if input_data is None: 64 return None 65 66 uniq = self.GetUniqueName() 67 output_fname = tools.GetOutputFilename('vblock.%s' % uniq) 68 input_fname = tools.GetOutputFilename('input.%s' % uniq) 69 tools.WriteFile(input_fname, input_data) 70 prefix = self.keydir + '/' 71 args = [ 72 'vbutil_firmware', 73 '--vblock', output_fname, 74 '--keyblock', prefix + self.keyblock, 75 '--signprivate', prefix + self.signprivate, 76 '--version', '%d' % self.version, 77 '--fv', input_fname, 78 '--kernelkey', prefix + self.kernelkey, 79 '--flags', '%d' % self.preamble_flags, 80 ] 81 #out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label)) 82 stdout = tools.Run('futility', *args) 83 return tools.ReadFile(output_fname) 84 85 def ObtainContents(self): 86 data = self.GetVblock(False) 87 if data is None: 88 return False 89 self.SetContents(data) 90 return True 91 92 def ProcessContents(self): 93 # The blob may have changed due to WriteSymbols() 94 data = self.GetVblock(True) 95 return self.ProcessContentsUpdate(data) 96