summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorNeha Malcom Francis <n-francis@ti.com>2023-05-25 15:47:14 +0530
committerPraneeth Bajjuri <praneeth@ti.com>2023-05-25 06:44:54 -0500
commitdd467d4f53808c92dd4b47d7e3f57825607670cf (patch)
treed41f492378e8d29f7db582e0c9d4428be847d38c /tools
parent96ff5709e43b12ace17065b72ed79d562974d8de (diff)
binman: ti-secure: Add support for TI signing
The ti-secure entry contains certificate for binaries that will be loaded or booted by system firmware whereas the ti-secure-rom entry contains certificate for binaries that will be booted by ROM. Support for both these types of certificates is necessary for booting of K3 devices. Signed-off-by: Neha Malcom Francis <n-francis@ti.com> Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/binman/btool/openssl.py244
-rw-r--r--tools/binman/entries.rst65
-rw-r--r--tools/binman/etype/ti_secure.py76
-rw-r--r--tools/binman/etype/ti_secure_rom.py247
-rw-r--r--tools/binman/etype/x509_cert.py87
-rw-r--r--tools/binman/ftest.py52
-rw-r--r--tools/binman/test/279_ti_secure.dts17
-rw-r--r--tools/binman/test/280_ti_secure_rom.dts17
-rw-r--r--tools/binman/test/281_ti_secure_rom_combined.dts25
-rw-r--r--tools/binman/test/288_ti_secure_rom_a.dts19
-rw-r--r--tools/binman/test/289_ti_secure_rom_b.dts18
11 files changed, 859 insertions, 8 deletions
diff --git a/tools/binman/btool/openssl.py b/tools/binman/btool/openssl.py
index 3a4dbdd6d7..aad3b61ae2 100644
--- a/tools/binman/btool/openssl.py
+++ b/tools/binman/btool/openssl.py
@@ -15,6 +15,13 @@ import hashlib
from binman import bintool
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 Bintoolopenssl(bintool.Bintool):
"""openssl tool
@@ -74,6 +81,243 @@ imageSize = INTEGER:{len(indata)}
'-sha512']
return self.run_cmd(*args)
+ def x509_cert_sysfw(self, cert_fname, input_fname, key_fname, sw_rev,
+ config_fname, req_dist_name_dict):
+ """Create a certificate to be booted by system firmware
+
+ Args:
+ cert_fname (str): Filename of certificate to create
+ input_fname (str): Filename containing data to sign
+ key_fname (str): Filename of .pem file
+ sw_rev (int): Software revision
+ config_fname (str): Filename to write fconfig into
+ req_dist_name_dict (dict): Dictionary containing key-value pairs of
+ req_distinguished_name section extensions, must contain extensions for
+ C, ST, L, O, OU, CN and emailAddress
+
+ Returns:
+ str: Tool output
+ """
+ indata = tools.read_file(input_fname)
+ hashval = hashlib.sha512(indata).hexdigest()
+ with open(config_fname, 'w', encoding='utf-8') as outf:
+ print(f'''[ req ]
+distinguished_name = req_distinguished_name
+x509_extensions = v3_ca
+prompt = no
+dirstring_type = nobmp
+
+[ req_distinguished_name ]
+C = {req_dist_name_dict['C']}
+ST = {req_dist_name_dict['ST']}
+L = {req_dist_name_dict['L']}
+O = {req_dist_name_dict['O']}
+OU = {req_dist_name_dict['OU']}
+CN = {req_dist_name_dict['CN']}
+emailAddress = {req_dist_name_dict['emailAddress']}
+
+[ v3_ca ]
+basicConstraints = CA:true
+1.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv
+1.3.6.1.4.1.294.1.34 = ASN1:SEQUENCE:sysfw_image_integrity
+1.3.6.1.4.1.294.1.35 = ASN1:SEQUENCE:sysfw_image_load
+
+[ swrv ]
+swrv = INTEGER:{sw_rev}
+
+[ sysfw_image_integrity ]
+shaType = OID:2.16.840.1.101.3.4.2.3
+shaValue = FORMAT:HEX,OCT:{hashval}
+imageSize = INTEGER:{len(indata)}
+
+[ sysfw_image_load ]
+destAddr = FORMAT:HEX,OCT:00000000
+authInPlace = INTEGER:2
+''', file=outf)
+ args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
+ '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
+ '-sha512']
+ return self.run_cmd(*args)
+
+ def x509_cert_rom(self, cert_fname, input_fname, key_fname, sw_rev,
+ config_fname, req_dist_name_dict, cert_type, bootcore,
+ bootcore_opts, load_addr, sha):
+ """Create a certificate
+
+ Args:
+ cert_fname (str): Filename of certificate to create
+ input_fname (str): Filename containing data to sign
+ key_fname (str): Filename of .pem file
+ sw_rev (int): Software revision
+ config_fname (str): Filename to write fconfig into
+ req_dist_name_dict (dict): Dictionary containing key-value pairs of
+ req_distinguished_name section extensions, must contain extensions for
+ C, ST, L, O, OU, CN and emailAddress
+ cert_type (int): Certification type
+ bootcore (int): Booting core
+ load_addr (int): Load address of image
+ sha (int): Hash function
+
+ Returns:
+ str: Tool output
+ """
+ indata = tools.read_file(input_fname)
+ hashval = hashlib.sha512(indata).hexdigest()
+ with open(config_fname, 'w', encoding='utf-8') as outf:
+ print(f'''
+[ req ]
+ distinguished_name = req_distinguished_name
+ x509_extensions = v3_ca
+ prompt = no
+ dirstring_type = nobmp
+
+ [ req_distinguished_name ]
+C = {req_dist_name_dict['C']}
+ST = {req_dist_name_dict['ST']}
+L = {req_dist_name_dict['L']}
+O = {req_dist_name_dict['O']}
+OU = {req_dist_name_dict['OU']}
+CN = {req_dist_name_dict['CN']}
+emailAddress = {req_dist_name_dict['emailAddress']}
+
+ [ v3_ca ]
+ basicConstraints = CA:true
+ 1.3.6.1.4.1.294.1.1 = ASN1:SEQUENCE:boot_seq
+ 1.3.6.1.4.1.294.1.2 = ASN1:SEQUENCE:image_integrity
+ 1.3.6.1.4.1.294.1.3 = ASN1:SEQUENCE:swrv
+# 1.3.6.1.4.1.294.1.4 = ASN1:SEQUENCE:encryption
+ 1.3.6.1.4.1.294.1.8 = ASN1:SEQUENCE:debug
+
+ [ boot_seq ]
+ certType = INTEGER:{cert_type}
+ bootCore = INTEGER:{bootcore}
+ bootCoreOpts = INTEGER:{bootcore_opts}
+ destAddr = FORMAT:HEX,OCT:{load_addr:08x}
+ imageSize = INTEGER:{len(indata)}
+
+ [ image_integrity ]
+ shaType = OID:{SHA_OIDS[sha]}
+ shaValue = FORMAT:HEX,OCT:{hashval}
+
+ [ swrv ]
+ swrv = INTEGER:{sw_rev}
+
+# [ encryption ]
+# initalVector = FORMAT:HEX,OCT:TEST_IMAGE_ENC_IV
+# randomString = FORMAT:HEX,OCT:TEST_IMAGE_ENC_RS
+# iterationCnt = INTEGER:TEST_IMAGE_KEY_DERIVE_INDEX
+# salt = FORMAT:HEX,OCT:TEST_IMAGE_KEY_DERIVE_SALT
+
+ [ debug ]
+ debugUID = FORMAT:HEX,OCT:0000000000000000000000000000000000000000000000000000000000000000
+ debugType = INTEGER:4
+ coreDbgEn = INTEGER:0
+ coreDbgSecEn = INTEGER:0
+''', file=outf)
+ args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
+ '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
+ '-sha512']
+ return self.run_cmd(*args)
+
+ def x509_cert_rom_combined(self, cert_fname, input_fname, key_fname, sw_rev,
+ config_fname, req_dist_name_dict, load_addr, sha, total_size, num_comps,
+ sysfw_inner_cert_ext_boot_sequence_string, dm_data_ext_boot_sequence_string,
+ imagesize_sbl, hashval_sbl, load_addr_sysfw, imagesize_sysfw,
+ hashval_sysfw, load_addr_sysfw_data, imagesize_sysfw_data,
+ hashval_sysfw_data, sysfw_inner_cert_ext_boot_block,
+ dm_data_ext_boot_block):
+ """Create a certificate
+
+ Args:
+ cert_fname (str): Filename of certificate to create
+ input_fname (str): Filename containing data to sign
+ key_fname (str): Filename of .pem file
+ sw_rev (int): Software revision
+ config_fname (str): Filename to write fconfig into
+ req_dist_name_dict (dict): Dictionary containing key-value pairs of
+ req_distinguished_name section extensions, must contain extensions for
+ C, ST, L, O, OU, CN and emailAddress
+ cert_type (int): Certification type
+ bootcore (int): Booting core
+ load_addr (int): Load address of image
+ sha (int): Hash function
+
+ Returns:
+ str: Tool output
+ """
+ indata = tools.read_file(input_fname)
+ hashval = hashlib.sha512(indata).hexdigest()
+ sha_type = SHA_OIDS[sha]
+ with open(config_fname, 'w', encoding='utf-8') as outf:
+ print(f'''
+[ req ]
+distinguished_name = req_distinguished_name
+x509_extensions = v3_ca
+prompt = no
+dirstring_type = nobmp
+
+[ req_distinguished_name ]
+C = {req_dist_name_dict['C']}
+ST = {req_dist_name_dict['ST']}
+L = {req_dist_name_dict['L']}
+O = {req_dist_name_dict['O']}
+OU = {req_dist_name_dict['OU']}
+CN = {req_dist_name_dict['CN']}
+emailAddress = {req_dist_name_dict['emailAddress']}
+
+[ v3_ca ]
+basicConstraints = CA:true
+1.3.6.1.4.1.294.1.3=ASN1:SEQUENCE:swrv
+1.3.6.1.4.1.294.1.9=ASN1:SEQUENCE:ext_boot_info
+
+[swrv]
+swrv=INTEGER:{sw_rev}
+
+[ext_boot_info]
+extImgSize=INTEGER:{total_size}
+numComp=INTEGER:{num_comps}
+sbl=SEQUENCE:sbl
+sysfw=SEQUENCE:sysfw
+sysfw_data=SEQUENCE:sysfw_data
+{sysfw_inner_cert_ext_boot_sequence_string}
+{dm_data_ext_boot_sequence_string}
+
+[sbl]
+compType = INTEGER:1
+bootCore = INTEGER:16
+compOpts = INTEGER:0
+destAddr = FORMAT:HEX,OCT:{load_addr:08x}
+compSize = INTEGER:{imagesize_sbl}
+shaType = OID:{sha_type}
+shaValue = FORMAT:HEX,OCT:{hashval_sbl}
+
+[sysfw]
+compType = INTEGER:2
+bootCore = INTEGER:0
+compOpts = INTEGER:0
+destAddr = FORMAT:HEX,OCT:{load_addr_sysfw:08x}
+compSize = INTEGER:{imagesize_sysfw}
+shaType = OID:{sha_type}
+shaValue = FORMAT:HEX,OCT:{hashval_sysfw}
+
+[sysfw_data]
+compType = INTEGER:18
+bootCore = INTEGER:0
+compOpts = INTEGER:0
+destAddr = FORMAT:HEX,OCT:{load_addr_sysfw_data:08x}
+compSize = INTEGER:{imagesize_sysfw_data}
+shaType = OID:{sha_type}
+shaValue = FORMAT:HEX,OCT:{hashval_sysfw_data}
+
+{sysfw_inner_cert_ext_boot_block}
+
+{dm_data_ext_boot_block}
+ ''', file=outf)
+ args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
+ '-outform', 'DER', '-out', cert_fname, '-config', config_fname,
+ '-sha512']
+ return self.run_cmd(*args)
+
def fetch(self, method):
"""Fetch handler for openssl
diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst
index 07a0bb8519..f9900fe6be 100644
--- a/tools/binman/entries.rst
+++ b/tools/binman/entries.rst
@@ -1701,6 +1701,71 @@ the included board config binaries. Example::
+.. _etype_ti_secure:
+
+Entry: ti-secure: Entry containing a TI x509 certificate binary
+---------------------------------------------------------------
+
+Properties / Entry arguments:
+ - content: List of phandles to entries to sign
+ - keyfile: Filename of file containing key to sign binary with
+ - sha: Hash function to be used for signing
+
+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.
+
+
+
+.. _etype_ti_secure_rom:
+
+Entry: ti-secure-rom: 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
+
+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.
+
+
+
.. _etype_u_boot:
Entry: u-boot: U-Boot flat binary
diff --git a/tools/binman/etype/ti_secure.py b/tools/binman/etype/ti_secure.py
new file mode 100644
index 0000000000..d115b2e1a9
--- /dev/null
+++ b/tools/binman/etype/ti_secure.py
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2022 Texas Instruments Incorporated - https://www.ti.com/
+# Written by Neha Malcom Francis <n-francis@ti.com>
+#
+
+# Support for generation of TI secured binary blobs
+
+from binman.entry import EntryArg
+from binman.etype.x509_cert import Entry_x509_cert
+
+from dtoc import fdt_util
+
+class Entry_ti_secure(Entry_x509_cert):
+ """Entry containing a TI x509 certificate binary
+
+ Properties / Entry arguments:
+ - content: List of phandles to entries to sign
+ - keyfile: Filename of file containing key to sign binary with
+ - sha: Hash function to be used for signing
+
+ 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.key_fname = self.GetEntryArgsOrProps([
+ EntryArg('keyfile', str)], required=True)[0]
+ self.sha = fdt_util.GetInt(self._node, 'sha', 512)
+ self.req_dist_name = {'C': 'US',
+ 'ST': 'TX',
+ 'L': 'Dallas',
+ 'O': 'Texas Instruments Incorporated',
+ 'OU': 'Processors',
+ 'CN': 'TI Support',
+ 'emailAddress': 'support@ti.com'}
+
+ 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
+ """
+ return super().GetCertificate(required=required, type='sysfw')
+
+ def ObtainContents(self):
+ 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.GetCertificate(True)
+ return self.ProcessContentsUpdate(data)
+
+ def AddBintools(self, btools):
+ super().AddBintools(btools)
+ self.openssl = self.AddBintool(btools, 'openssl')
diff --git a/tools/binman/etype/ti_secure_rom.py b/tools/binman/etype/ti_secure_rom.py
new file mode 100644
index 0000000000..fc4999cc04
--- /dev/null
+++ b/tools/binman/etype/ti_secure_rom.py
@@ -0,0 +1,247 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2022 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
+
+ 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.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.core == 'secure':
+ if self.countersign:
+ self.cert_type = 3
+ else:
+ self.cert_type = 2
+ self.bootcore = 0
+ self.bootcore_opts = 32
+ else:
+ self.cert_type = 1
+ self.bootcore = 16
+ self.bootcore_opts = 0
+ 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]
+
+ # 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.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.GetCertificate(True)
+ return self.ProcessContentsUpdate(data)
+
+ def AddBintools(self, btools):
+ super().AddBintools(btools)
+ self.openssl = self.AddBintool(btools, 'openssl')
diff --git a/tools/binman/etype/x509_cert.py b/tools/binman/etype/x509_cert.py
index f80a6ec2d1..d028cfe38c 100644
--- a/tools/binman/etype/x509_cert.py
+++ b/tools/binman/etype/x509_cert.py
@@ -31,6 +31,26 @@ class Entry_x509_cert(Entry_collection):
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
self.openssl = None
+ self.req_dist_name = None
+ self.cert_type = None
+ self.bootcore = None
+ self.bootcore_opts = None
+ self.load_addr = None
+ self.sha = None
+ self.total_size = None
+ self.num_comps = None
+ self.sysfw_inner_cert_ext_boot_sequence_string = None
+ self.dm_data_ext_boot_sequence_string = None
+ self.imagesize_sbl = None
+ self.hashval_sbl = None
+ self.load_addr_sysfw = None
+ self.imagesize_sysfw = None
+ self.hashval_sysfw = None
+ self.load_addr_sysfw_data = None
+ self.imagesize_sysfw_data = None
+ self.hashval_sysfw_data = None
+ self.sysfw_inner_cert_ext_boot_block = None
+ self.dm_data_ext_boot_block = None
def ReadNode(self):
super().ReadNode()
@@ -38,13 +58,16 @@ class Entry_x509_cert(Entry_collection):
self._cert_rev = fdt_util.GetInt(self._node, 'cert-revision-int', 0)
self.key_fname = self.GetEntryArgsOrProps([
EntryArg('keyfile', str)], required=True)[0]
+ self.sw_rev = fdt_util.GetInt(self._node, 'sw-rev', 1)
- def GetCertificate(self, required):
+ def GetCertificate(self, required, type='generic'):
"""Get the contents of this entry
Args:
required: True if the data must be present, False if it is OK to
return None
+ type: Type of x509 certificate to generate, current supported ones are
+ 'generic', 'sysfw', 'rom'
Returns:
bytes content of the entry, which is the signed vblock for the
@@ -60,13 +83,61 @@ class Entry_x509_cert(Entry_collection):
input_fname = tools.get_output_filename('input.%s' % uniq)
config_fname = tools.get_output_filename('config.%s' % uniq)
tools.write_file(input_fname, input_data)
- stdout = self.openssl.x509_cert(
- cert_fname=output_fname,
- input_fname=input_fname,
- key_fname=self.key_fname,
- cn=self._cert_ca,
- revision=self._cert_rev,
- config_fname=config_fname)
+ if type == 'generic':
+ stdout = self.openssl.x509_cert(
+ cert_fname=output_fname,
+ input_fname=input_fname,
+ key_fname=self.key_fname,
+ cn=self._cert_ca,
+ revision=self._cert_rev,
+ config_fname=config_fname)
+ elif type == 'sysfw':
+ stdout = self.openssl.x509_cert_sysfw(
+ cert_fname=output_fname,
+ input_fname=input_fname,
+ key_fname=self.key_fname,
+ config_fname=config_fname,
+ sw_rev=self.sw_rev,
+ req_dist_name_dict=self.req_dist_name)
+ elif type == 'rom':
+ stdout = self.openssl.x509_cert_rom(
+ cert_fname=output_fname,
+ input_fname=input_fname,
+ key_fname=self.key_fname,
+ config_fname=config_fname,
+ sw_rev=self.sw_rev,
+ req_dist_name_dict=self.req_dist_name,
+ cert_type=self.cert_type,
+ bootcore=self.bootcore,
+ bootcore_opts=self.bootcore_opts,
+ load_addr=self.load_addr,
+ sha=self.sha
+ )
+ elif type == 'rom-combined':
+ stdout = self.openssl.x509_cert_rom_combined(
+ cert_fname=output_fname,
+ input_fname=input_fname,
+ key_fname=self.key_fname,
+ config_fname=config_fname,
+ sw_rev=self.sw_rev,
+ req_dist_name_dict=self.req_dist_name,
+ load_addr=self.load_addr,
+ sha=self.sha,
+ total_size=self.total_size,
+ num_comps=self.num_comps,
+ sysfw_inner_cert_ext_boot_sequence_string=self.sysfw_inner_cert_ext_boot_sequence_string,
+ dm_data_ext_boot_sequence_string=self.dm_data_ext_boot_sequence_string,
+ imagesize_sbl=self.imagesize_sbl,
+ hashval_sbl=self.hashval_sbl,
+ load_addr_sysfw=self.load_addr_sysfw,
+ imagesize_sysfw=self.imagesize_sysfw,
+ hashval_sysfw=self.hashval_sysfw,
+ load_addr_sysfw_data=self.load_addr_sysfw_data,
+ imagesize_sysfw_data=self.imagesize_sysfw_data,
+ hashval_sysfw_data=self.hashval_sysfw_data,
+ sysfw_inner_cert_ext_boot_block=self.sysfw_inner_cert_ext_boot_block,
+ dm_data_ext_boot_block=self.dm_data_ext_boot_block
+ )
if stdout is not None:
data = tools.read_file(output_fname)
else:
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index d895e08883..1555ce9898 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -98,6 +98,7 @@ PRE_LOAD_MAGIC = b'UBSH'
PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+TI_UNSECURE_DATA = b'unsecuredata'
# Subdirectory of the input dir to use to put test FDTs
TEST_FDT_SUBDIR = 'fdts'
@@ -211,6 +212,7 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
+ TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
# Add a few .dtb files for testing
TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
@@ -6451,5 +6453,55 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
data = self._DoReadFile('279_ti_board_cfg_no_type.dts')
self.assertIn("Schema validation error", str(e.exception))
+ def testPackTiSecure(self):
+ """Test that an image with a TI secured binary can be created"""
+ keyfile = self.TestFile('key.key')
+ entry_args = {
+ 'keyfile': keyfile,
+ }
+ data = self._DoReadFileDtb('279_ti_secure.dts',
+ entry_args=entry_args)[0]
+ self.assertGreater(len(data), len(TI_UNSECURE_DATA))
+
+ def testPackTiSecureMissingTool(self):
+ """Test that an image with a TI secured binary (non-functional) can be created
+ when openssl is missing"""
+ keyfile = self.TestFile('key.key')
+ entry_args = {
+ 'keyfile': keyfile,
+ }
+ with test_util.capture_sys_output() as (_, stderr):
+ self._DoTestFile('279_ti_secure.dts',
+ force_missing_bintools='openssl',
+ entry_args=entry_args)
+ err = stderr.getvalue()
+ self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
+
+ def testPackTiSecureROM(self):
+ """Test that a ROM image with a TI secured binary can be created"""
+ keyfile = self.TestFile('key.key')
+ entry_args = {
+ 'keyfile': keyfile,
+ }
+ data = self._DoReadFileDtb('280_ti_secure_rom.dts',
+ entry_args=entry_args)[0]
+ data_a = self._DoReadFileDtb('288_ti_secure_rom_a.dts',
+ entry_args=entry_args)[0]
+ data_b = self._DoReadFileDtb('289_ti_secure_rom_b.dts',
+ entry_args=entry_args)[0]
+ self.assertGreater(len(data), len(TI_UNSECURE_DATA))
+ self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
+ self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
+
+ def testPackTiSecureROMCombined(self):
+ """Test that a ROM image with a TI secured binary can be created"""
+ keyfile = self.TestFile('key.key')
+ entry_args = {
+ 'keyfile': keyfile,
+ }
+ data = self._DoReadFileDtb('281_ti_secure_rom_combined.dts',
+ entry_args=entry_args)[0]
+ self.assertGreater(len(data), len(TI_UNSECURE_DATA))
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/test/279_ti_secure.dts b/tools/binman/test/279_ti_secure.dts
new file mode 100644
index 0000000000..941d0ab4ca
--- /dev/null
+++ b/tools/binman/test/279_ti_secure.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ti-secure {
+ content = <&unsecure_binary>;
+ };
+ unsecure_binary: blob-ext {
+ filename = "ti_unsecure.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/280_ti_secure_rom.dts b/tools/binman/test/280_ti_secure_rom.dts
new file mode 100644
index 0000000000..d1313769f4
--- /dev/null
+++ b/tools/binman/test/280_ti_secure_rom.dts
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ti-secure-rom {
+ content = <&unsecure_binary>;
+ };
+ unsecure_binary: blob-ext {
+ filename = "ti_unsecure.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/281_ti_secure_rom_combined.dts b/tools/binman/test/281_ti_secure_rom_combined.dts
new file mode 100644
index 0000000000..bf872739bc
--- /dev/null
+++ b/tools/binman/test/281_ti_secure_rom_combined.dts
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ti-secure-rom {
+ content = <&unsecure_binary>;
+ content-sbl = <&unsecure_binary>;
+ content-sysfw = <&unsecure_binary>;
+ content-sysfw-data = <&unsecure_binary>;
+ content-sysfw-inner-cert = <&unsecure_binary>;
+ content-dm-data = <&unsecure_binary>;
+ combined;
+ sysfw-inner-cert;
+ dm-data;
+ };
+ unsecure_binary: blob-ext {
+ filename = "ti_unsecure.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/288_ti_secure_rom_a.dts b/tools/binman/test/288_ti_secure_rom_a.dts
new file mode 100644
index 0000000000..887138f0e4
--- /dev/null
+++ b/tools/binman/test/288_ti_secure_rom_a.dts
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ti-secure-rom {
+ content = <&unsecure_binary>;
+ core = "secure";
+ countersign;
+ };
+ unsecure_binary: blob-ext {
+ filename = "ti_unsecure.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/289_ti_secure_rom_b.dts b/tools/binman/test/289_ti_secure_rom_b.dts
new file mode 100644
index 0000000000..c6d6182158
--- /dev/null
+++ b/tools/binman/test/289_ti_secure_rom_b.dts
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ti-secure-rom {
+ content = <&unsecure_binary>;
+ core = "public";
+ };
+ unsecure_binary: blob-ext {
+ filename = "ti_unsecure.bin";
+ };
+ };
+};