aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2024-01-04 16:53:49 -0500
committerTom Rini <trini@konsulko.com>2024-01-04 16:53:49 -0500
commit0d53be75c701d00ea3a106db1f3e5cca8c05068f (patch)
treecd4c9e98ecc97bc2c0a04d4c524a1398a57eb3d9 /tools
parent42fb448a203197c84d71a5d8f83012c87c5c9a8b (diff)
parent7ff09d484e5ca11934bec8023f10062a336e61b5 (diff)
downloadu-boot-0d53be75c701d00ea3a106db1f3e5cca8c05068f.zip
u-boot-0d53be75c701d00ea3a106db1f3e5cca8c05068f.tar.gz
u-boot-0d53be75c701d00ea3a106db1f3e5cca8c05068f.tar.bz2
Merge patch series "ATF and OP-TEE Firewalling for K3 devices."WIP/04Jan2024-next
Manorit Chawdhry <m-chawdhry@ti.com> says: K3 devices have firewalls that are used to prevent illegal accesses to memory regions that are deemed secure. The series prevents the illegal accesses to ATF and OP-TEE regions that are present in different K3 devices. AM62X, AM62AX and AM64X are currently in hold due to some firewall configurations that our System Controller (TIFS) needs to handle. The devices that are not configured with the firewalling nodes will not be affected and can continue to work fine until the firewall nodes are added so will be a non-blocking merge. Test Logs: https://gist.github.com/manorit2001/4cead2fb3a19eb5d19005b3f54682627 CICD Run: https://github.com/u-boot/u-boot/pull/442
Diffstat (limited to 'tools')
-rw-r--r--tools/binman/btool/openssl.py16
-rw-r--r--tools/binman/etype/ti_secure.py95
-rw-r--r--tools/binman/etype/x509_cert.py4
-rw-r--r--tools/binman/ftest.py23
-rw-r--r--tools/binman/test/324_ti_secure_firewall.dts28
-rw-r--r--tools/binman/test/325_ti_secure_firewall_missing_property.dts28
-rw-r--r--tools/dtoc/fdt.py2
7 files changed, 192 insertions, 4 deletions
diff --git a/tools/binman/btool/openssl.py b/tools/binman/btool/openssl.py
index 7ee2683..fe81a1f 100644
--- a/tools/binman/btool/openssl.py
+++ b/tools/binman/btool/openssl.py
@@ -82,7 +82,7 @@ imageSize = INTEGER:{len(indata)}
return self.run_cmd(*args)
def x509_cert_sysfw(self, cert_fname, input_fname, key_fname, sw_rev,
- config_fname, req_dist_name_dict):
+ config_fname, req_dist_name_dict, firewall_cert_data):
"""Create a certificate to be booted by system firmware
Args:
@@ -94,6 +94,13 @@ imageSize = INTEGER:{len(indata)}
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
+ firewall_cert_data (dict):
+ - auth_in_place (int): The Priv ID for copying as the
+ specific host in firewall protected region
+ - num_firewalls (int): The number of firewalls in the
+ extended certificate
+ - certificate (str): Extended firewall certificate with
+ the information for the firewall configurations.
Returns:
str: Tool output
@@ -121,6 +128,7 @@ 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
+1.3.6.1.4.1.294.1.37 = ASN1:SEQUENCE:firewall
[ swrv ]
swrv = INTEGER:{sw_rev}
@@ -132,7 +140,11 @@ imageSize = INTEGER:{len(indata)}
[ sysfw_image_load ]
destAddr = FORMAT:HEX,OCT:00000000
-authInPlace = INTEGER:2
+authInPlace = INTEGER:{hex(firewall_cert_data['auth_in_place'])}
+
+[ firewall ]
+numFirewallRegions = INTEGER:{firewall_cert_data['num_firewalls']}
+{firewall_cert_data['certificate']}
''', file=outf)
args = ['req', '-new', '-x509', '-key', key_fname, '-nodes',
'-outform', 'DER', '-out', cert_fname, '-config', config_fname,
diff --git a/tools/binman/etype/ti_secure.py b/tools/binman/etype/ti_secure.py
index d939dce..704dcf8 100644
--- a/tools/binman/etype/ti_secure.py
+++ b/tools/binman/etype/ti_secure.py
@@ -7,9 +7,44 @@
from binman.entry import EntryArg
from binman.etype.x509_cert import Entry_x509_cert
+from dataclasses import dataclass
from dtoc import fdt_util
+@dataclass
+class Firewall():
+ id: int
+ region: int
+ control : int
+ permissions: list
+ start_address: str
+ end_address: str
+
+ def ensure_props(self, etype, name):
+ missing_props = []
+ for key, val in self.__dict__.items():
+ if val is None:
+ missing_props += [key]
+
+ if len(missing_props):
+ etype.Raise(f"Subnode '{name}' is missing properties: {','.join(missing_props)}")
+
+ def get_certificate(self) -> str:
+ unique_identifier = f"{self.id}{self.region}"
+ cert = f"""
+firewallID{unique_identifier} = INTEGER:{self.id}
+region{unique_identifier} = INTEGER:{self.region}
+control{unique_identifier} = INTEGER:{hex(self.control)}
+nPermissionRegs{unique_identifier} = INTEGER:{len(self.permissions)}
+"""
+ for index, permission in enumerate(self.permissions):
+ cert += f"""permissions{unique_identifier}{index} = INTEGER:{hex(permission)}
+"""
+ cert += f"""startAddress{unique_identifier} = FORMAT:HEX,OCT:{self.start_address:02x}
+endAddress{unique_identifier} = FORMAT:HEX,OCT:{self.end_address:02x}
+"""
+ return cert
+
class Entry_ti_secure(Entry_x509_cert):
"""Entry containing a TI x509 certificate binary
@@ -17,6 +52,11 @@ class Entry_ti_secure(Entry_x509_cert):
- 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
+ - auth-in-place: This is an integer field that contains two pieces
+ of information
+ Lower Byte - Remains 0x02 as per our use case
+ ( 0x02: Move the authenticated binary back to the header )
+ Upper Byte - The Host ID of the core owning the firewall
Output files:
- input.<unique_name> - input file passed to openssl
@@ -25,6 +65,35 @@ class Entry_ti_secure(Entry_x509_cert):
- cert.<unique_name> - output file generated by openssl (which is
used as the entry contents)
+ Depending on auth-in-place information in the inputs, we read the
+ firewall nodes that describe the configurations of firewall that TIFS
+ will be doing after reading the certificate.
+
+ The syntax of the firewall nodes are as such:
+
+ firewall-257-0 {
+ id = <257>; /* The ID of the firewall being configured */
+ region = <0>; /* Region number to configure */
+
+ control = /* The control register */
+ <(FWCTRL_EN | FWCTRL_LOCK | FWCTRL_BG | FWCTRL_CACHE)>;
+
+ permissions = /* The permission registers */
+ <((FWPRIVID_ALL << FWPRIVID_SHIFT) |
+ FWPERM_SECURE_PRIV_RWCD |
+ FWPERM_SECURE_USER_RWCD |
+ FWPERM_NON_SECURE_PRIV_RWCD |
+ FWPERM_NON_SECURE_USER_RWCD)>;
+
+ /* More defines can be found in k3-security.h */
+
+ start_address = /* The Start Address of the firewall */
+ <0x0 0x0>;
+ end_address = /* The End Address of the firewall */
+ <0xff 0xffffffff>;
+ };
+
+
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.
@@ -32,11 +101,20 @@ class Entry_ti_secure(Entry_x509_cert):
def __init__(self, section, etype, node):
super().__init__(section, etype, node)
self.openssl = None
+ self.firewall_cert_data: dict = {
+ 'auth_in_place': 0x02,
+ 'num_firewalls': 0,
+ 'certificate': '',
+ }
def ReadNode(self):
super().ReadNode()
self.key_fname = self.GetEntryArgsOrProps([
EntryArg('keyfile', str)], required=True)[0]
+ auth_in_place = fdt_util.GetInt(self._node, 'auth-in-place')
+ if auth_in_place:
+ self.firewall_cert_data['auth_in_place'] = auth_in_place
+ self.ReadFirewallNode()
self.sha = fdt_util.GetInt(self._node, 'sha', 512)
self.req_dist_name = {'C': 'US',
'ST': 'TX',
@@ -46,6 +124,23 @@ class Entry_ti_secure(Entry_x509_cert):
'CN': 'TI Support',
'emailAddress': 'support@ti.com'}
+ def ReadFirewallNode(self):
+ self.firewall_cert_data['certificate'] = ""
+ self.firewall_cert_data['num_firewalls'] = 0
+ for node in self._node.subnodes:
+ if 'firewall' in node.name:
+ firewall = Firewall(
+ fdt_util.GetInt(node, 'id'),
+ fdt_util.GetInt(node, 'region'),
+ fdt_util.GetInt(node, 'control'),
+ fdt_util.GetPhandleList(node, 'permissions'),
+ fdt_util.GetInt64(node, 'start_address'),
+ fdt_util.GetInt64(node, 'end_address'),
+ )
+ firewall.ensure_props(self, node.name)
+ self.firewall_cert_data['num_firewalls'] += 1
+ self.firewall_cert_data['certificate'] += firewall.get_certificate()
+
def GetCertificate(self, required):
"""Get the contents of this entry
diff --git a/tools/binman/etype/x509_cert.py b/tools/binman/etype/x509_cert.py
index fc0bb12..29630d1 100644
--- a/tools/binman/etype/x509_cert.py
+++ b/tools/binman/etype/x509_cert.py
@@ -51,6 +51,7 @@ class Entry_x509_cert(Entry_collection):
self.hashval_sysfw_data = None
self.sysfw_inner_cert_ext_boot_block = None
self.dm_data_ext_boot_block = None
+ self.firewall_cert_data = None
def ReadNode(self):
super().ReadNode()
@@ -98,7 +99,8 @@ class Entry_x509_cert(Entry_collection):
key_fname=self.key_fname,
config_fname=config_fname,
sw_rev=self.sw_rev,
- req_dist_name_dict=self.req_dist_name)
+ req_dist_name_dict=self.req_dist_name,
+ firewall_cert_data=self.firewall_cert_data)
elif type == 'rom':
stdout = self.openssl.x509_cert_rom(
cert_fname=output_fname,
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index a4ac520..9048251 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -7052,6 +7052,29 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
entry_args=entry_args)[0]
self.assertGreater(len(data), len(TI_UNSECURE_DATA))
+ def testPackTiSecureFirewall(self):
+ """Test that an image with a TI secured binary can be created"""
+ keyfile = self.TestFile('key.key')
+ entry_args = {
+ 'keyfile': keyfile,
+ }
+ data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
+ entry_args=entry_args)[0]
+ data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
+ entry_args=entry_args)[0]
+ self.assertGreater(len(data_firewall),len(data_no_firewall))
+
+ def testPackTiSecureFirewallMissingProperty(self):
+ """Test that an image with a TI secured binary can be created"""
+ keyfile = self.TestFile('key.key')
+ entry_args = {
+ 'keyfile': keyfile,
+ }
+ with self.assertRaises(ValueError) as e:
+ data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
+ entry_args=entry_args)[0]
+ self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
+
def testPackTiSecureMissingTool(self):
"""Test that an image with a TI secured binary (non-functional) can be created
when openssl is missing"""
diff --git a/tools/binman/test/324_ti_secure_firewall.dts b/tools/binman/test/324_ti_secure_firewall.dts
new file mode 100644
index 0000000..7ec407f
--- /dev/null
+++ b/tools/binman/test/324_ti_secure_firewall.dts
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ti-secure {
+ content = <&unsecure_binary>;
+ auth-in-place = <0xa02>;
+
+ firewall-0-2 {
+ id = <0>;
+ region = <2>;
+ control = <0x31a>;
+ permissions = <0xc3ffff>;
+ start_address = <0x0 0x9e800000>;
+ end_address = <0x0 0x9fffffff>;
+ };
+
+ };
+ unsecure_binary: blob-ext {
+ filename = "ti_unsecure.bin";
+ };
+ };
+};
diff --git a/tools/binman/test/325_ti_secure_firewall_missing_property.dts b/tools/binman/test/325_ti_secure_firewall_missing_property.dts
new file mode 100644
index 0000000..24a0a99
--- /dev/null
+++ b/tools/binman/test/325_ti_secure_firewall_missing_property.dts
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ ti-secure {
+ content = <&unsecure_binary>;
+ auth-in-place = <0xa02>;
+
+ firewall-0-2 {
+ // id = <0>;
+ // region = <2>;
+ control = <0x31a>;
+ permissions = <0xc3ffff>;
+ start_address = <0x0 0x9e800000>;
+ end_address = <0x0 0x9fffffff>;
+ };
+
+ };
+ unsecure_binary: blob-ext {
+ filename = "ti_unsecure.bin";
+ };
+ };
+};
diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py
index 5963925..991a36b 100644
--- a/tools/dtoc/fdt.py
+++ b/tools/dtoc/fdt.py
@@ -782,7 +782,7 @@ class Node:
for node in parent.subnodes.__reversed__():
dst = self.copy_node(node)
- tout.debug(f'merge props from {parent.path} to {dst.path}')
+ tout.debug(f'merge props from {parent.path} to {self.path}')
self.merge_props(parent, False)