blob: f6fc3f90f84ab1b0a9c806a966d508abfd6f3eee [file] [log] [blame]
# SPDX-License-Identifier: GPL-2.0+
# Copyright (c) 2022-2023 Texas Instruments Incorporated - https://www.ti.com/
# Written by Neha Malcom Francis <n-francis@ti.com>
#
# Support for generation of TI secured bootloaders booted by ROM
from binman.entry import EntryArg
from binman.etype.x509_cert import Entry_x509_cert
import hashlib
from dtoc import fdt_util
from u_boot_pylib import tools
VALID_SHAS = [256, 384, 512, 224]
SHA_OIDS = {256:'2.16.840.1.101.3.4.2.1',
384:'2.16.840.1.101.3.4.2.2',
512:'2.16.840.1.101.3.4.2.3',
224:'2.16.840.1.101.3.4.2.4'}
class Entry_ti_secure_rom(Entry_x509_cert):
"""Entry containing a TI x509 certificate binary for images booted by ROM
Properties / Entry arguments:
- keyfile: Filename of file containing key to sign binary with
- combined: boolean if device follows combined boot flow
- countersign: boolean if device contains countersigned system firmware
- load: load address of SPL
- sw-rev: software revision
- sha: Hash function to be used for signing
- core: core on which bootloader runs, valid cores are 'secure' and 'public'
- content: phandle of SPL in case of legacy bootflow or phandles of component binaries
in case of combined bootflow
- core-opts (optional): lockstep (0) or split (2) mode set to 0 by default
The following properties are only for generating a combined bootflow binary:
- sysfw-inner-cert: boolean if binary contains sysfw inner certificate
- dm-data: boolean if binary contains dm-data binary
- content-sbl: phandle of SPL binary
- content-sysfw: phandle of sysfw binary
- content-sysfw-data: phandle of sysfw-data or tifs-data binary
- content-sysfw-inner-cert (optional): phandle of sysfw inner certificate binary
- content-dm-data (optional): phandle of dm-data binary
- load-sysfw: load address of sysfw binary
- load-sysfw-data: load address of sysfw-data or tifs-data binary
- load-sysfw-inner-cert (optional): load address of sysfw inner certificate binary
- load-dm-data (optional): load address of dm-data binary
Output files:
- input.<unique_name> - input file passed to openssl
- config.<unique_name> - input file generated for openssl (which is
used as the config file)
- cert.<unique_name> - output file generated by openssl (which is
used as the entry contents)
openssl signs the provided data, using the TI templated config file and
writes the signature in this entry. This allows verification that the
data is genuine.
"""
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
self.openssl = None
def ReadNode(self):
super().ReadNode()
self.combined = fdt_util.GetBool(self._node, 'combined', False)
self.countersign = fdt_util.GetBool(self._node, 'countersign', False)
self.load_addr = fdt_util.GetInt(self._node, 'load', 0x00000000)
self.sw_rev = fdt_util.GetInt(self._node, 'sw-rev', 1)
self.sha = fdt_util.GetInt(self._node, 'sha', 512)
self.core = fdt_util.GetString(self._node, 'core', 'secure')
self.bootcore_opts = fdt_util.GetInt(self._node, 'core-opts')
self.key_fname = self.GetEntryArgsOrProps([
EntryArg('keyfile', str)], required=True)[0]
if self.combined:
self.sysfw_inner_cert = fdt_util.GetBool(self._node, 'sysfw-inner-cert', False)
self.load_addr_sysfw = fdt_util.GetInt(self._node, 'load-sysfw', 0x00000000)
self.load_addr_sysfw_data = fdt_util.GetInt(self._node, 'load-sysfw-data', 0x00000000)
self.dm_data = fdt_util.GetBool(self._node, 'dm-data', False)
if self.dm_data:
self.load_addr_dm_data = fdt_util.GetInt(self._node, 'load-dm-data', 0x00000000)
self.req_dist_name = {'C': 'US',
'ST': 'TX',
'L': 'Dallas',
'O': 'Texas Instruments Incorporated',
'OU': 'Processors',
'CN': 'TI Support',
'emailAddress': 'support@ti.com'}
def NonCombinedGetCertificate(self, required):
"""Generate certificate for legacy boot flow
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 certificate binary for the
provided data
"""
if self.bootcore_opts is None:
self.bootcore_opts = 0
if self.core == 'secure':
if self.countersign:
self.cert_type = 3
else:
self.cert_type = 2
self.bootcore = 0
else:
self.cert_type = 1
self.bootcore = 16
return super().GetCertificate(required=required, type='rom')
def CombinedGetCertificate(self, required):
"""Generate certificate for combined boot flow
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 certificate binary for the
provided data
"""
uniq = self.GetUniqueName()
self.num_comps = 3
self.sha_type = SHA_OIDS[self.sha]
if self.bootcore_opts is None:
self.bootcore_opts = 0
# sbl
self.content = fdt_util.GetPhandleList(self._node, 'content-sbl')
input_data_sbl = self.GetContents(required)
if input_data_sbl is None:
return None
input_fname_sbl = tools.get_output_filename('input.%s' % uniq)
tools.write_file(input_fname_sbl, input_data_sbl)
indata_sbl = tools.read_file(input_fname_sbl)
self.hashval_sbl = hashlib.sha512(indata_sbl).hexdigest()
self.imagesize_sbl = len(indata_sbl)
# sysfw
self.content = fdt_util.GetPhandleList(self._node, 'content-sysfw')
input_data_sysfw = self.GetContents(required)
input_fname_sysfw = tools.get_output_filename('input.%s' % uniq)
tools.write_file(input_fname_sysfw, input_data_sysfw)
indata_sysfw = tools.read_file(input_fname_sysfw)
self.hashval_sysfw = hashlib.sha512(indata_sysfw).hexdigest()
self.imagesize_sysfw = len(indata_sysfw)
# sysfw data
self.content = fdt_util.GetPhandleList(self._node, 'content-sysfw-data')
input_data_sysfw_data = self.GetContents(required)
input_fname_sysfw_data = tools.get_output_filename('input.%s' % uniq)
tools.write_file(input_fname_sysfw_data, input_data_sysfw_data)
indata_sysfw_data = tools.read_file(input_fname_sysfw_data)
self.hashval_sysfw_data = hashlib.sha512(indata_sysfw_data).hexdigest()
self.imagesize_sysfw_data = len(indata_sysfw_data)
# sysfw inner cert
self.sysfw_inner_cert_ext_boot_block = ""
self.sysfw_inner_cert_ext_boot_sequence_string = ""
imagesize_sysfw_inner_cert = 0
if self.sysfw_inner_cert:
self.content = fdt_util.GetPhandleList(self._node, 'content-sysfw-inner-cert')
input_data_sysfw_inner_cert = self.GetContents(required)
input_fname_sysfw_inner_cert = tools.get_output_filename('input.%s' % uniq)
tools.write_file(input_fname_sysfw_inner_cert, input_data_sysfw_inner_cert)
indata_sysfw_inner_cert = tools.read_file(input_fname_sysfw_inner_cert)
hashval_sysfw_inner_cert = hashlib.sha512(indata_sysfw_inner_cert).hexdigest()
imagesize_sysfw_inner_cert = len(indata_sysfw_inner_cert)
self.num_comps += 1
self.sysfw_inner_cert_ext_boot_sequence_string = "sysfw_inner_cert=SEQUENCE:sysfw_inner_cert"
self.sysfw_inner_cert_ext_boot_block = f"""[sysfw_inner_cert]
compType = INTEGER:3
bootCore = INTEGER:0
compOpts = INTEGER:0
destAddr = FORMAT:HEX,OCT:00000000
compSize = INTEGER:{imagesize_sysfw_inner_cert}
shaType = OID:{self.sha_type}
shaValue = FORMAT:HEX,OCT:{hashval_sysfw_inner_cert}"""
# dm data
self.dm_data_ext_boot_sequence_string = ""
self.dm_data_ext_boot_block = ""
imagesize_dm_data = 0
if self.dm_data:
self.content = fdt_util.GetPhandleList(self._node, 'content-dm-data')
input_data_dm_data = self.GetContents(required)
input_fname_dm_data = tools.get_output_filename('input.%s' % uniq)
tools.write_file(input_fname_dm_data, input_data_dm_data)
indata_dm_data = tools.read_file(input_fname_dm_data)
hashval_dm_data = hashlib.sha512(indata_dm_data).hexdigest()
imagesize_dm_data = len(indata_dm_data)
self.num_comps += 1
self.dm_data_ext_boot_sequence_string = "dm_data=SEQUENCE:dm_data"
self.dm_data_ext_boot_block = f"""[dm_data]
compType = INTEGER:17
bootCore = INTEGER:16
compOpts = INTEGER:0
destAddr = FORMAT:HEX,OCT:{self.load_addr_dm_data:08x}
compSize = INTEGER:{imagesize_dm_data}
shaType = OID:{self.sha_type}
shaValue = FORMAT:HEX,OCT:{hashval_dm_data}"""
self.total_size = self.imagesize_sbl + self.imagesize_sysfw + self.imagesize_sysfw_data + imagesize_sysfw_inner_cert + imagesize_dm_data
return super().GetCertificate(required=required, type='rom-combined')
def GetCertificate(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 certificate binary for the
provided data
"""
if self.combined:
return self.CombinedGetCertificate(required)
else:
return self.NonCombinedGetCertificate(required)
def ObtainContents(self):
data = self.data
if data is None:
data = self.GetCertificate(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.data
return self.ProcessContentsUpdate(data)
def AddBintools(self, btools):
super().AddBintools(btools)
self.openssl = self.AddBintool(btools, 'openssl')