--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+MIIBWwIBAAKBgQDRfrnXQaP0k6vRK/gZ+bDflSU6y1JagGeQ/b+QYuiDz14japog
+8fRSu5WBsAxaSaySAUwS3L9Ppw+hGMecmyIJ494aMfZTtk1g49gU58joduiRnu7e
+QSZHMnehhuNlfD7A2tAAKnxIYuabs8zHYM/SS9Ne7t3kIQMbKfUSzNy6qQIBAQIB
+AQJBAOelUA376o6w3HkShXfN+shaOZYqFuTJ9exLMwsLp7DZKXB5F9I4JJ+Vkvho
+k6QWs7vkhleLSYUZknXHYm26ZE0CQQDnhTtd4PTBoZPjPXOeYMJFtEdMNy0XP6ey
+bcce389ugoY7BEkvASrd8PHgJQHziepgWOG4DGp33c64Hfq4zI3NAgEBAgEBAkA0
+RbK4uqoLciQluesTPU6lBy7Se3Dw0F9xBqlF5SR4KI6q+zQrHpBKyFOofMHZgizR
+iCrL55cxEM146zMw3AnF
+-----END RSA PRIVATE KEY-----
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
'-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
+.. _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
--- /dev/null
+# 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 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.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')
--- /dev/null
+# 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
+
+ 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.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')
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()
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
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:
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'
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,
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()
--- /dev/null
+// 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";
+ };
+ };
+};
--- /dev/null
+// 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";
+ };
+ };
+};
--- /dev/null
+// 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";
+ };
+ };
+};
--- /dev/null
+// 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";
+ };
+ };
+};
--- /dev/null
+// 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";
+ };
+ };
+};