Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | # 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 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 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 - 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 - 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) 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. """ 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', 'L': 'Dallas', 'O': 'Texas Instruments Incorporated', 'OU': 'Processors', 'CN': 'TI Support', 'emailAddress': 'support@ti.com'} self.debug = fdt_util.GetBool(self._node, 'debug', False) 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 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') |