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 | # SPDX-License-Identifier: GPL-2.0+ # Copyright 2023 Google LLC # Written by Simon Glass <sjg@chromium.org> # # Support for an X509 certificate, used to sign a set of entries from collections import OrderedDict import os from binman.entry import EntryArg from binman.etype.collection import Entry_collection from dtoc import fdt_util from u_boot_pylib import tools class Entry_x509_cert(Entry_collection): """An entry which contains an X509 certificate Properties / Entry arguments: - content: List of phandles to entries to sign Output files: - input.<unique_name> - input file passed to openssl - cert.<unique_name> - output file generated by openssl (which is used as the entry contents) openssl signs the provided data, writing 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.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 self.firewall_cert_data = None self.debug = False def ReadNode(self): super().ReadNode() self._cert_ca = fdt_util.GetString(self._node, 'cert-ca') 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, 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 provided data """ # Join up the data files to be signed input_data = self.GetContents(required) if input_data is None: return None uniq = self.GetUniqueName() output_fname = tools.get_output_filename('cert.%s' % uniq) 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 = None 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, firewall_cert_data=self.firewall_cert_data) 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, debug=self.debug ) 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, bootcore_opts=self.bootcore_opts, debug=self.debug ) if stdout is not None: data = tools.read_file(output_fname) else: # Bintool is missing; just use 4KB of zero data self.record_missing_bintool(self.openssl) data = tools.get_bytes(0, 4096) return data 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') |