
core-secdev-k3 is the TI security development package provided for K3 platform devices. This tool helps sign bootloader images with the x509 ceritificate header.
Signed-off-by: Neha Malcom Francis n-francis@ti.com --- This patch depends on https://patchwork.ozlabs.org/project/uboot/patch/20230224115101.563729-1-n-f... and on ongoing development in https://git.ti.com/cgit/security-development-tools/core-secdev-k3
tools/binman/btool/tisecuretool.py | 72 +++++++++++ tools/binman/etype/ti_secure.py | 114 ++++++++++++++++++ tools/binman/ftest.py | 36 ++++++ tools/binman/test/278_ti_secure_rom.dts | 11 ++ tools/binman/test/279_ti_secure.dts | 11 ++ .../binman/test/280_ti_secure_nofilename.dts | 10 ++ tools/binman/test/281_ti_secure_combined.dts | 12 ++ 7 files changed, 266 insertions(+) create mode 100644 tools/binman/btool/tisecuretool.py create mode 100644 tools/binman/etype/ti_secure.py create mode 100644 tools/binman/test/278_ti_secure_rom.dts create mode 100644 tools/binman/test/279_ti_secure.dts create mode 100644 tools/binman/test/280_ti_secure_nofilename.dts create mode 100644 tools/binman/test/281_ti_secure_combined.dts
diff --git a/tools/binman/btool/tisecuretool.py b/tools/binman/btool/tisecuretool.py new file mode 100644 index 0000000000..5102bb1f7d --- /dev/null +++ b/tools/binman/btool/tisecuretool.py @@ -0,0 +1,72 @@ +# 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 +# +"""Bintool implementation for TI security development tools + +tisecuretool helps add x509 certification for bootloader images for K3 platform devices + +Source code: +https://git.ti.com/cgit/security-development-tools/core-secdev-k3/""" + +import os + +from binman import bintool +from patman import tout +from patman import tools + +class Bintooltisecuretool(bintool.Bintool): + """Signing tool for TI bootloaders""" + name = 'tisecuretool' + def __init__(self, name): + super().__init__(name, 'TI secure tool') + + def sign_binary_secure(self, fname, out_fname): + """Create a signed binary + + Args: + fname (str): Filename to sign + out_fname (str): Output filename + + Returns: + str: Tool output + or None + """ + tool_path = self.get_path() + script_path = os.path.join(tool_path, 'scripts/secure-binary-image.sh') + args = [ + 'sh', + script_path, + fname, + out_fname + ] + output = self.run_cmd(*args, add_name=False) + return output + + def sign_binary_rom(self, args): + """Create a signed binary that is booted by ROM + + Args: + fname (str): Filename to sign + out_fname (str): Output filename""" + tool_path = self.get_path() + script_path = os.path.join(tool_path, 'scripts/secure-rom-boot-image.sh') + #args.insert(0, script_path) + args.insert(0, script_path) + output = self.run_cmd(*args, add_name=False) + return output + + def fetch(self, method): + """Fetch handler for TI secure tool + + This builds the tool from source + + Returns: + True if the file was fetched, None if a method other than FETCH_SOURCE + was requested + """ + if method != bintool.FETCH_SOURCE: + return None + result = self.fetch_from_git( + 'git://git.ti.com/security-development-tools/core-secdev-k3.git', 'tisecuretool') + return result diff --git a/tools/binman/etype/ti_secure.py b/tools/binman/etype/ti_secure.py new file mode 100644 index 0000000000..26f81ff8e8 --- /dev/null +++ b/tools/binman/etype/ti_secure.py @@ -0,0 +1,114 @@ +# 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 +# +# Entry-type module for signed binaries for TI K3 platform +# + +from binman.etype.blob import Entry_blob +from binman import bintool + +from dtoc import fdt_util +from patman import terminal +from patman import tools +from patman import tout + +class Entry_ti_secure(Entry_blob): + """An entry which contains a signed x509 binary for signing TI + General Purpose as well as High-Security devices. + + Properties / Entry arguments: + - filename: filename of binary file to be secured + + Output files: + - filename_x509 - output file generated by secure x509 signing script (which + used as entry contents) + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self.filename = fdt_util.GetString(self._node, 'filename') + self.core = fdt_util.GetString(self._node, 'core', 'secure') + self.load_addr = fdt_util.GetInt(self._node, 'load', 0x41c00000) + self.sw_rev = fdt_util.GetInt(self._node, 'sw-rev', 1) + self.sysfw_cert = fdt_util.GetBool(self._node, 'sysfw-cert', False) + self.secure = fdt_util.GetBool(self._node, 'secure', False) + self.combined = fdt_util.GetBool(self._node, 'combined', False) + self.split_dm = fdt_util.GetBool(self._node, 'split-dm', False) + self.sysfw_filename = fdt_util.GetString(self._node, 'sysfw-filename') + self.sysfw_load_addr = fdt_util.GetInt(self._node, 'sysfw-load', 0x40000) + self.sysfw_data_filename = fdt_util.GetString(self._node, 'sysfw-data-filename') + self.sysfw_data_load_addr = fdt_util.GetInt(self._node, 'sysfw-data-load', 0x7f000) + self.sysfw_inner_cert = fdt_util.GetString(self._node, 'sysfw-inner-cert', "") + self.dm_data_filename = fdt_util.GetString(self._node, 'dm-data-filename') + self.dm_data_load_addr = fdt_util.GetInt(self._node, 'dm-data-load', 0x41c80000) + self.sysfw_inner_cert_filename = fdt_util.GetString(self._node, 'sysfw-inner-cert-filename') + self.toolpresent = False + if not self.filename: + self.Raise("ti_secure must have a 'filename' property") + + def _SignBinarySecure(self): + infilename = self.filename + outfilename = infilename + '_signed' + + data = self.tisecuretool.sign_binary_secure(infilename, outfilename) + + if data is None: + # Bintool is missing, create a zeroed binary + self.record_missing_bintool(self.tisecuretool) + return tools.get_bytes(0, 1024) + + return tools.read_file(outfilename) + + def _SignBinaryROM(self): + input_fname = self.filename + output_fname = input_fname + "_x509" + if self.combined: + args = [ + '-b', input_fname, + '-l', hex(self.load_addr), + '-s', self.sysfw_filename, + '-m', hex(self.sysfw_load_addr), + '-a', self.sysfw_inner_cert, + '-d', self.sysfw_data_filename, + '-n', hex(self.sysfw_data_load_addr), + '-r', str(self.sw_rev), + '-o', output_fname, + ] + if self.split_dm: + args.extend(['-t', self.dm_data_filename, '-y', hex(self.dm_data_load_addr)]) + else: + args = [ + '-a', self.core, + '-b', input_fname, + '-o', output_fname, + '-l', hex(self.load_addr), + '-r', str(self.sw_rev), + + ] + if self.sysfw_cert == True: + args.insert(0, '-u') + + out = self.tisecuretool.sign_binary_rom(args) + + if out is None: + # Bintool is missing, create a zeroed binary + self.record_missing_bintool(self.tisecuretool) + return tools.get_bytes(0, 1024) + + return tools.read_file(output_fname) + + def ProcessContents(self): + if self.secure: + data = self._SignBinarySecure() + else: + data = self._SignBinaryROM() + return self.ProcessContentsUpdate(data) + + def AddBintools(self, btools): + #super().AddBintools(btools) + col = terminal.Color() + self.tisecuretool = self.AddBintool(btools, 'tisecuretool') + out = self.tisecuretool.fetch_tool(bintool.FETCH_SOURCE, col, True) + if out == bintool.FAIL: + # Bintool is missing, record missing + self.record_missing_bintool(self.tisecuretool) \ No newline at end of file diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index bf902341c5..72cce0ef02 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -97,6 +97,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\x01' +TIX509DATA = b'letsgo'
# Subdirectory of the input dir to use to put test FDTs TEST_FDT_SUBDIR = 'fdts' @@ -206,6 +207,7 @@ class TestFunctional(unittest.TestCase): TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA) TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA) TestFunctional._MakeInputFile('scp.bin', SCP_DATA) + TestFunctional._MakeInputFile('to_sign.bin', TIX509DATA)
# Add a few .dtb files for testing TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR, @@ -6398,5 +6400,39 @@ fdt fdtmap Extract the devicetree blob from the fdtmap configlen_noheader = TI_BOARD_CONFIG_DATA*4 self.assertGreater(data, configlen_noheader)
+ def testTISecureROMImageMissingTool(self): + """Test that a TI secure signed ROM booted image can be generated although tisecuretool is missing""" + with test_util.capture_sys_output() as (_, stderr): + data = self._DoTestFile('278_ti_secure_rom.dts', + force_missing_bintools='tisecuretool') + err = stderr.getvalue() + self.assertRegex(err, + "Image 'image'.*missing bintools.*: tisecuretool") + + def testTISecureImageMissingTool(self): + """Test that a TI secure signed image can be generated although tisecuretool is missing""" + with test_util.capture_sys_output() as (_, stderr): + data = self._DoTestFile('279_ti_secure.dts', + force_missing_bintools='tisecuretool') + err = stderr.getvalue() + self.assertRegex(err, + "Image 'image'.*missing bintools.*: tisecuretool") + + def testTISecureNoFilename(self): + """Test that a missing 'filename' property is detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('280_ti_secure_nofilename.dts') + self.assertIn("ti_secure must have a 'filename' property", + str(e.exception)) + + def testTISecureImageCombinedMissingTool(self): + """Test that a TI secure signed image can be generated although tisecuretool is missing""" + with test_util.capture_sys_output() as (_, stderr): + data = self._DoTestFile('281_ti_secure_combined.dts', + force_missing_bintools='tisecuretool') + err = stderr.getvalue() + self.assertRegex(err, + "Image 'image'.*missing bintools.*: tisecuretool") + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/278_ti_secure_rom.dts b/tools/binman/test/278_ti_secure_rom.dts new file mode 100644 index 0000000000..67a6a9de8d --- /dev/null +++ b/tools/binman/test/278_ti_secure_rom.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + ti-secure { + filename = "to_sign.bin"; + sysfw-cert; + }; + }; +}; diff --git a/tools/binman/test/279_ti_secure.dts b/tools/binman/test/279_ti_secure.dts new file mode 100644 index 0000000000..0e60984013 --- /dev/null +++ b/tools/binman/test/279_ti_secure.dts @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + ti-secure { + filename = "to_sign.bin"; + secure; + }; + }; +}; diff --git a/tools/binman/test/280_ti_secure_nofilename.dts b/tools/binman/test/280_ti_secure_nofilename.dts new file mode 100644 index 0000000000..928a50a499 --- /dev/null +++ b/tools/binman/test/280_ti_secure_nofilename.dts @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + ti-secure { + secure; + }; + }; +}; diff --git a/tools/binman/test/281_ti_secure_combined.dts b/tools/binman/test/281_ti_secure_combined.dts new file mode 100644 index 0000000000..aadb5a4306 --- /dev/null +++ b/tools/binman/test/281_ti_secure_combined.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + ti-secure { + filename = "to_sign.bin"; + combined; + split-dm; + }; + }; +};