def __init__(self, debug_dir, hash_algorithm, data=None, images=None): self.debug_dir = debug_dir self._initialize(hash_algorithm, images) # Validate hash algorithm if self.hash_algorithm not in ENCODE_HASH_ALGO: raise RuntimeError(multi_image_string() + " segment does not support configured segment_hash_algorithm {0}".format(self.hash_algorithm)) # Validate that required information is provided if data is None and not images: raise RuntimeError("When creating a " + multi_image_string() + " segment at least one of the following must be provided:\n" "\t1) An existing " + multi_image_string() + " segment\n" "\t2) Images to add to (or update) in the " + multi_image_string() + " segment") if data: self._unpack(data) if images: self._update()
def __repr__(self): def segment_properties(seg, segment_name): if seg: return segment_name + ' Segment Properties: ' + '\n' + repr(seg) + '\n' else: return '' return ('Base Properties: ' + '\n' + properties_repr(self._repr_properties()) + '\n' 'ELF Properties: ' + '\n' + repr(self._elf_parsegen) + '\n' 'Hash Segment Properties: ' + '\n' + repr(self._mbn_parsegen) + '\n' + segment_properties(self._multi_image_segment, multi_image_string()))
def _update(self): def get_hash(data): from sectools.features.isc.signer.utils.hmac import HMAC h = HMAC.HASH_ALGO_MAP[self.hash_algorithm]() h.update(data) return h.digest() for image in self.images_to_add_or_update: sw_id = int(image.imageinfo.sw_id, 16) app_id = image.imageinfo.app_id app_id_normalized = int(app_id, 16) if app_id is not None else 0 data = image.get_multi_image_entry_data(image.authority) if not data: raise RuntimeError("Cannot add image entry to " + multi_image_string() + " segment for image with SW_ID={0} because it has no hash segment.".format(hex(sw_id))) # Update existing hash entry if (sw_id, app_id_normalized) in self.image_hash_dict.keys(): if app_id is None: logger.info("Updated " + multi_image_string() + " entry for image with SW_ID={0}".format(hex(sw_id))) else: logger.info("Updated " + multi_image_string() + " entry for image with SW_ID={0} and APP_ID={1}".format(hex(sw_id), hex(app_id_normalized))) # Add new hash entry else: if app_id is None: logger.info("Added " + multi_image_string() + " entry for image with SW_ID={0}".format(hex(sw_id))) else: logger.info("Added " + multi_image_string() + " entry for image with SW_ID={0} and APP_ID={1}".format(hex(sw_id), hex(app_id_normalized))) self.image_hash_dict[(sw_id, app_id_normalized)] = get_hash(data) if len(self.image_hash_dict) > MAX_NUM_IMAGES: raise RuntimeError(multi_image_string() + " segment cannot contains {0} image entries." "\nMaximum allowed number of images entries is {1}.".format(len(self.image_hash_dict), MAX_NUM_IMAGES))
def _unpack(self, data): # Validate size of segment is not smaller than allowed minimum min_size_of_hash_entry = min(HASH_ALGO_TO_SIZE_MAP.values()) min_size = self._get_fixed_size() + self._get_id_size() + min_size_of_hash_entry if len(data) < min_size: raise RuntimeError(multi_image_string() + " segment is of invalid size {0} bytes." "\nMinimum allowed size is {1} bytes.".format(len(data), min_size)) # Extract segment header offset = 0 end = self._get_fixed_size() (self.magic_number, self.version, self.res0, self.res1, self.res2, self.res3, self.res4, self.res5, self.res6, self.res7, self.res8, self.res9, self.res10, self.res11, self.res12, self.res13, self.res14, self.res15, self.res16, self.res17, self.res18, self.res19, self.res20, self.res21, self.res22, self.res23, self.res24, self.res25, self.res26, self.res27, self.res28, self.res29, self.res30, self.res31, num_images, hash_algorithm,) = struct.unpack(self._get_fixed_format(), data[offset:end]) # Validate extracted values if self.magic_number != MAGIC_NUM: raise RuntimeError(multi_image_string() + " segment contains invalid magic number {0}." "\nMagic number must be {1}.".format(self.magic_number, MAGIC_NUM)) if self.version != MULT_IMAGE_VERSION_0: raise RuntimeError(multi_image_string() + " segment contains invalid version number {0}." "\nSupported version are: {1}.".format(self.version, SUPPORTED_VERSIONS)) if num_images > MAX_NUM_IMAGES: raise RuntimeError(multi_image_string() + " segment contains {0} image entries." "\nMaximum allowed number of images entries is {1}.".format(num_images, MAX_NUM_IMAGES)) if hash_algorithm not in DECODE_HASH_ALGO: raise RuntimeError(multi_image_string() + " segment contains invalid hash algorithm value {0}." "\nAllowed hash algorithm values are {1}.".format(hash_algorithm, DECODE_HASH_ALGO.keys())) elif DECODE_HASH_ALGO[hash_algorithm] != self.hash_algorithm: raise RuntimeError(multi_image_string() + " segment was created using {0} but segment_hash_algorithm is configured to {1}." "\nChange configured segment_hash_algorithm value to {0}.".format(DECODE_HASH_ALGO[hash_algorithm], self.hash_algorithm)) # Validate segment size expected_size = self._get_fixed_size() + (self._get_id_size() + HASH_ALGO_TO_SIZE_MAP[self.hash_algorithm]) * num_images if expected_size < len(data): raise RuntimeError(multi_image_string() + " segment is of invalid size {0} bytes." "\nSegment containing {1} {2} image entries should be {} bytes.".format(len(data), num_images, self.hash_algorithm, expected_size)) # Extract sw_id/app_id and hash values for i in range(num_images): offset = end end += self._get_id_size() (sw_id, app_id,) = struct.unpack(self._get_id_format(), data[offset:end]) hash_size = HASH_ALGO_TO_SIZE_MAP[self.hash_algorithm] offset = end end += hash_size image_hash = data[offset:end] self.image_hash_dict[(sw_id, app_id)] = image_hash store_debug_data_to_file(FILE_EXTRACTED, data[0:end], self.debug_dir) store_debug_data_to_file(FILE_EXTRACTED_READABLE, str(self), self.debug_dir)
def get_multi_image_entry_data(self, authority): logger.debug("Getting data to hash for " + authority + " " + multi_image_string() + " entry") try: if self.is_signed(): return self.data_to_sign else: header = self._mbn_parsegen.header # Copy the MBN header so that masking doesn't alter original header header = copy_header(header) # Mask metadata and sig/cert sizes of other authority header = self.utils.mask_header_values(header, self.authority) return header.pack() + self._mbn_parsegen.code except: return None
def _extract_existing_multi_image_segment(self): multi_image_segment, multi_image_entry = None, None # Find the phdr entry for the multi image segment for phdr in self._elf_parsegen.phdrs: if phdr.p_type == PT_LOAD: if multi_image_entry is None: multi_image_entry = phdr self.mem_size = phdr.p_memsz else: raise RuntimeError(multi_image_string() + " image contains " "multiple LOAD segments.\n " "Only 1 LOAD segment is allowed to exist.") # Extract segment data and remove segment if multi_image_entry: multi_image_segment = self._elf_parsegen.get_segment_data(multi_image_entry) self._elf_parsegen.remove_segment(multi_image_entry) return multi_image_segment
def _validate_properties(self): self.errors = [] sa = self.signing_attributes if not POLICY_OEM_ID_0.is_ignore(): if int(sa.oem_id, 16) == 0: POLICY_OEM_ID_0.run('OEM ID is set to 0 for sign_id "' + str(self.sign_id) + '"') # Secboot v1 requires oem permissions only if sa.secboot_version == SECBOOT_VERSION_1_0: if not sa.oem_sign: # oem_sign cannot be false for secboot v1 self._add_error( 'OEM operations cannot be disabled for a Secure Boot ' + str(SECBOOT_VERSION_1_0) + ' image.') if sa.qti_sign: # qti_sign cannot be true for secboot v1 self._add_error( 'Cannot perform QTI operations on a Secure Boot ' + str(SECBOOT_VERSION_1_0) + ' image.') # If all authority permissions are disabled, throw error elif not sa.qti_sign and not sa.oem_sign: self._add_error( 'Cannot perform image operations because OEM and QTI operations are disabled for image.' ) # Raise warnings for Secboot v2.1 and greater chipsets if self.chipset in SECBOOT_2_0_DOUBLE_SIGN_CHIPSETS + SECBOOT_3_0_DOUBLE_SIGN_CHIPSETS: if int(sa.rot_en, 16) == 1: logger.warning( "rot_en should not be set to \"{0}\" for chipset \"{1}\".". format(sa.rot_en, self.chipset)) if sa.hash_algorithm == "sha1": logger.warning( "hash_algorithm should not be set to \"{0}\" for chipset \"{1}\"." .format(sa.hash_algorithm, self.chipset)) if sa.exponent == 3: logger.warning( "exponent should not be set to \"{0}\" for chipset \"{1}\"." .format(sa.exponent, self.chipset)) if sa.dsa_type == "ecdsa": sa.rsa_padding = None else: if sa.rsa_padding == "pkcs": logger.warning( "rsa_padding should not be set to RSAPKCS for chipset \"{0}\"." .format(self.chipset)) # Ignore max_num_root_certs value if target is not MRC v2.0 double sign target if not (self.chipset in MRC_2_0_CHIPSETS and sa.qti_sign and sa.oem_sign): sa.max_num_root_certs = None # Ignore max_num_certs_in_certchain if image is not double signable if not (sa.qti_sign and sa.oem_sign): sa.max_num_certs_in_certchain = None if self.is_multi_image and sa.multi_image_segment_addr is None: self._add_error( advanced_defines.multi_image_string() + " operation requires multi_image_segment_addr config value.") if sa.secboot_version == SECBOOT_VERSION_3_0: # Secboot 3 only support sha256 and sha384 for attr_name in ["hash_algorithm", "segment_hash_algorithm"]: if getattr(sa, attr_name) not in ["sha256", "sha384"]: self._add_error( "Secure Boot {0} requires 'sha256' or 'sha384' {1}.". format(sa.secboot_version, attr_name)) multi_serial_numbers = sa.multi_serial_numbers.serial if sa.multi_serial_numbers is not None else [] self._validate_serial_bound_value(sa.crash_dump, "crash_dump", chipset=self.chipset, ignore_num_root_certs=True, allowed_lsb_values=[0, 1]) self._validate_serial_bound_value( sa.rot_en, "rot_en", chipset=self.chipset, ignore_num_root_certs=True, disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0, additional_serials_are_bindable=len(multi_serial_numbers) > 0, allowed_lsb_values=[0, 1]) # Validate uie_key_switch_enable self._validate_serial_bound_value( sa.uie_key_switch_enable, "uie_key_switch_enable", chipset=self.chipset, ignore_num_root_certs=True, disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0, additional_serials_are_bindable=len(multi_serial_numbers) > 0) # MRC 1.0 use case # Validate revocation_enablement self._validate_serial_bound_value(sa.revocation_enablement, "revocation_enablement", chipset=self.chipset, allowed_chipsets=MRC_1_0_CHIPSETS, num_root_certs=sa.num_root_certs) # Validate activation_enablement self._validate_serial_bound_value(sa.activation_enablement, "activation_enablement", chipset=self.chipset, allowed_chipsets=MRC_1_0_CHIPSETS, num_root_certs=sa.num_root_certs) # MRC 2.0 use case # Validate root_revoke_activate_enable self._validate_serial_bound_value( sa.root_revoke_activate_enable, "root_revoke_activate_enable", chipset=self.chipset, allowed_chipsets=MRC_2_0_CHIPSETS, num_root_certs=sa.num_root_certs, disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0, additional_serials_are_bindable=len(multi_serial_numbers) > 0) self._validate_serial_bound_value( sa.debug, "debug", chipset=self.chipset, ignore_num_root_certs=True, disable_in_value_binding=sa.secboot_version == SECBOOT_VERSION_3_0, additional_serials_are_bindable=len(multi_serial_numbers) > 0, allowed_lsb_values=[0, 2, 3] if sa.secboot_version != SECBOOT_VERSION_3_0 else None, require_serial_number=(self.verbatim_config or len(self.valid_serial_numbers) == 0)) if self.errors: raise RuntimeError("".join(self.errors))
from sectools.features.isc.encryption_service.unified.encdec import UIE_2_0_L2_1_2_IDENT from sectools.features.isc.encryption_service.unified.encdec import UNIFIED_ENCRYPTION_IDENT from .imageinfo_base import DestImagePathBase from .imageinfo_base import ImageInfoBase from .imageinfo_base import ImageStatusBase from .imageinfo_base import debug_only from .imageinfo_utils import StatusInfo from .imageinfo_utils import resolve_enumerated from .serial_binding_features import MAX_NUM_SERIALS_MAP from .serial_binding_features import SerialBoundFeatureSetContextManager from ..cfgparser import auto_gen_obj_config as agoc from ..cfgparser import defines as cfgdef from ..parsegen.config import auto_gen_obj_config as pgagoc POLICY_OEM_ID_0 = ValPolicy(ValPolicy.WARN) MULTI_IMAGE_FILENAME = advanced_defines.multi_image_string() + " image" OEM_MULTI_IMAGE_SIGN_ID = "multi_image" QTI_MULTI_IMAGE_SIGN_ID = "multi_image_qti" MULTI_IMAGE_SIGN_ID = { defines.AUTHORITY_OEM: OEM_MULTI_IMAGE_SIGN_ID, advanced_defines.AUTHORITY_QTI: QTI_MULTI_IMAGE_SIGN_ID, } MAX_NUM_SOC_VERS_10 = 10 MAX_NUM_SOC_VERS_12 = 12 MAX_NUM_SOC_VERS_MAP = { SECBOOT_VERSION_1_0: MAX_NUM_SOC_VERS_10, SECBOOT_VERSION_2_0: MAX_NUM_SOC_VERS_10, SECBOOT_VERSION_3_0: MAX_NUM_SOC_VERS_12 }
def __init__(self, image_path, img_config_parser, parsegen_config, authority, sign_id=None, gen_multi_image=False, multi_image_path=None, crypto_params={}, imageinfo_class=None, verbatim_config=False, disable_serial_binding=False, platform_binding=None): assert isinstance(image_path, str) assert isinstance(img_config_parser, ConfigParser) assert isinstance(parsegen_config, ParsegenCfgParser) if sign_id is not None: assert isinstance(sign_id, str) # Initialize the BaseStager super(ImagePathsStager, self).__init__(authority) # Validate that the image path exists image_path = c_path.normalize(image_path) if not c_path.validate_file(image_path): raise RuntimeError('No read access to the image path: ' + image_path) # Put the image info object into the list imageinfo = self._create_imageinfo( img_config_parser, parsegen_config, sign_id, image_path, gen_multi_image=False, crypto_params=crypto_params, imageinfo_class=imageinfo_class, verbatim_config=verbatim_config, disable_serial_binding=disable_serial_binding, platform_binding=platform_binding) self._image_info_list.append(imageinfo) # Validate that the Multi-Image Sign & Integrity image path exists if multi_image_path is not None: multi_image_path = c_path.normalize(multi_image_path) if not c_path.validate_file(multi_image_path): raise RuntimeError('No read access to the ' + multi_image_string() + ' image path: ' + multi_image_path) # Set sign id to Multi-Image image's sign id sign_id = MULTI_IMAGE_SIGN_ID[authority] # Set the Multi-Image Signing & Integrity image's imageinfo multi_image_imageinfo = self._create_imageinfo( img_config_parser, parsegen_config, sign_id=sign_id, image_path=multi_image_path, gen_multi_image=False, imageinfo_class=imageinfo_class, platform_binding=platform_binding) self._multi_image_imageinfo_dict[ multi_image_imageinfo.chipset] = multi_image_imageinfo # Create image info object for to-be-created Multi-Image Signing and Integrity image elif gen_multi_image: # Set sign id to Multi-Image Sign & Integrity image's sign id sign_id = MULTI_IMAGE_SIGN_ID[authority] # Set the Multi-Image Signing & Integrity image's imageinfo multi_image_imageinfo = self._create_imageinfo( img_config_parser, parsegen_config, sign_id, None, gen_multi_image, imageinfo_class=imageinfo_class, platform_binding=platform_binding) self._multi_image_imageinfo_dict[ multi_image_imageinfo.chipset] = multi_image_imageinfo
def print_summary(args, image_info_list, multi_image_imageinfo_list): """Prints the summary of the actions performed by SecImage""" if not image_info_list: return # Check which actions were performed actions = [] multi_image_actions = [] if args.no_op: actions.append('parse') if args.integrity_check: actions.append('integrity_check') if args.sign: actions.append('sign') if args.encrypt: actions.append('encrypt') if args.validate: actions.append('validate') if multi_image_imageinfo_list: if args.m_integrity_check: multi_image_actions.append('integrity_check') if args.m_sign: multi_image_actions.append('sign') if args.m_encrypt: multi_image_actions.append('encrypt') if args.m_validate: multi_image_actions.append('validate') if not (actions + multi_image_actions): return # Figure out the output directory output_print = (('Output is saved at: ' + args.output_dir + '\n') if args.output_dir else ('Minimized build was updated at: ' + args.mini_build + '\n') if args.mini_build else '\n') # Log the actions and output directory actions_str = ('Following actions were performed: "' + ', '.join(actions) + '"' + '\n') if actions else '' multi_image_actions_str = ('Following ' + multi_image_string() + ' actions were performed: "' + ', '.join(multi_image_actions) + '"' + '\n') if multi_image_actions else '' logger.info('SUMMARY:' + '\n' + actions_str + multi_image_actions_str + output_print) # Table information summary_table = TablePrinter([1]) # summary_table = TablePrinter([0]) COLUMN_IDX = 0 COLUMN_SIGN_ID = 1 COLUMN_PARSE = 2 COLUMN_INTEGRITY_CHECK = 3 COLUMN_SIGN = 4 COLUMN_ENCRYPT = 5 COLUMN_VAL_PARSE = 6 COLUMN_VAL_INTEGRITY_CHECK = 7 COLUMN_VAL_SIGN = 8 COLUMN_VAL_ENCRYPT = 9 # First row summary_table.insert_data(0, COLUMN_IDX, 'Idx') summary_table.insert_data(0, COLUMN_SIGN_ID, 'SignId') summary_table.insert_data(0, COLUMN_PARSE, 'Parse') summary_table.insert_data(0, COLUMN_INTEGRITY_CHECK, 'Integrity') summary_table.insert_data(0, COLUMN_SIGN, 'Sign') summary_table.insert_data(0, COLUMN_ENCRYPT, 'Encrypt') summary_table.insert_data(0, COLUMN_VAL_PARSE, 'Validate', column_end=COLUMN_VAL_ENCRYPT) # Second row summary_table.insert_data(1, COLUMN_VAL_PARSE, 'Parse') summary_table.insert_data(1, COLUMN_VAL_INTEGRITY_CHECK, 'Integrity') summary_table.insert_data(1, COLUMN_VAL_SIGN, 'Sign') summary_table.insert_data(1, COLUMN_VAL_ENCRYPT, 'Encrypt') # Data rows for idx, image in enumerate(image_info_list + list(multi_image_imageinfo_list)): idx += 2 summary_table.insert_data(idx, COLUMN_IDX, str(idx - 1) + '.') summary_table.insert_data(idx, COLUMN_SIGN_ID, image.sign_id) summary_table.insert_data(idx, COLUMN_PARSE, image.status.parsegen.state) summary_table.insert_data(idx, COLUMN_INTEGRITY_CHECK, image.status.integrity_check.state) summary_table.insert_data(idx, COLUMN_SIGN, image.status.sign.state) summary_table.insert_data(idx, COLUMN_ENCRYPT, image.status.encrypt.state) summary_table.insert_data(idx, COLUMN_VAL_PARSE, image.status.validate_parsegen.state) summary_table.insert_data(idx, COLUMN_VAL_INTEGRITY_CHECK, image.status.validate_integrity_check.state) summary_table.insert_data(idx, COLUMN_VAL_SIGN, image.status.validate_sign.state) summary_table.insert_data(idx, COLUMN_VAL_ENCRYPT, image.status.validate_encrypt.state) logger.info(summary_table.get_data())
def c_validate(self): """Validates the command line args provided by the user. :raises: RuntimeError if any error occurs. """ args = self.parsed_args err = [] # Check the input files if ((args.image_file and args.meta_build) or (not args.image_file and not args.meta_build)): err.append( 'Provide either image_file or a meta_build for processing.') # Check that m_image_file and meta_build are not both provided if args.meta_build and args.m_image_file: err.append('--m_image_file cannot be provided with meta_build.') err.append('Provide --m_gen flag if ' + multi_image_string() + ' file generation is desired.') # Check that m_gen and m_image_file are not both provided if args.m_gen and args.m_image_file: err.append('Provide either --m_image_file or --m_gen.') # Check that --override flag is not given without help flag if args.overrides and not args.help: err.append( '-h flag must accompany --overrides flag to view overridable properties' ) # Check if the meta build supports sign id meta_supports_sign_id = False if args.meta_build: meta_supports_sign_id = SecImageCore.meta_supports_sign_id( args.meta_build) # Check the configuration option and output dir if args.image_file or (args.meta_build and not meta_supports_sign_id): if ((args.chipset and args.config_path) or (not args.chipset and not args.config_path)): err.append( 'Provide either chipset or a config_path to process images.' ) if not args.output_dir: err.append('Provide the output_dir for storing the output.') elif args.meta_build and not meta_supports_sign_id: if not args.output_dir and not args.mini_build: err.append( 'Provide either output_dir or mini_build for storing the output.' ) if args.integrity_check or args.sign or args.encrypt: args.validate = True elif not (args.decrypt or args.validate or args.verify_inputs or args.no_op): err.append('Specify one or more operations to perform.') # Check that multi-image operations are enabled when m_gen or m_image_file are provided if args.m_image_file and not (args.m_integrity_check or args.m_sign or args.m_encrypt or args.m_decrypt or args.m_validate): err.append('Specify one or more ' + multi_image_string() + ' image operations to perform.') if args.m_gen and not (args.m_integrity_check or args.m_sign or args.m_encrypt): err.append('Specify one or more ' + multi_image_string() + ' image operations to perform.') # Check that multi-image operations are not enabled when m_gen and m_image_file are missing if not (args.m_gen or args.m_image_file) and ( args.m_integrity_check or args.m_sign or args.m_encrypt or args.m_decrypt or args.m_validate): err.append( 'Provide either --m_image_file or --m_gen when performing ' + multi_image_string() + ' image operations.') # When m_gen, m_integrity_check, m_sign or m_encrypt is enabled, enforce m_validate if args.m_integrity_check or args.m_sign or args.m_encrypt: args.m_validate = True # Check that no_op operation is only enabled when m_gen or m_image_file are provided if args.no_op and not (args.m_gen or args.m_image_file): err.append( 'Provide either --m_image_file or --m_gen when adding image entry to ' + multi_image_string() + ' image.') # Check that no_op operation is not provided with any other individual image operations if args.no_op and (args.integrity_check or args.sign or args.encrypt or args.decrypt or args.validate): err.append( 'no_op operation cannot be performed alongside other image operations' ) if args.rch in rch_string and not args.qti_signing: err.append( comma_separated_string(rch_string, final_separator='and') + ' root certificate hash validation is not supported for OEM signatures' ) # Check sign_attr is only set when adding hash table if args.sign_attr and not (args.integrity_check or args.sign): err.append( 'sign_attr operation can only be performed when integrity_check or sign are being performed.' ) # Check m_sign_attr is only set when adding hash table if args.m_sign_attr and not (args.m_integrity_check or args.m_sign): err.append( 'm_sign_attr operation can only be performed when m_integrity_check or m_sign are being performed.' ) # --verbatim_config and --serial_numbers are mutually exclusive. if args.verbatim_config and args.serial_numbers: err.append( '--verbatim_config cannot be provided with --serial_numbers.') # Check and sanitize any paths for read access for path in ['image_file', 'config_path']: path_val = getattr(args, path, None) if path_val: path_val = c_path.normalize(path_val) if not c_path.validate_file(path_val): err.append('Cannot access ' + path + ' at: ' + path_val) setattr(args, path, path_val) # Check and sanitize any paths for read dir access for path in ['meta_build']: path_val = getattr(args, path, None) if path_val: path_val = c_path.normalize(path_val) if not c_path.validate_dir(path_val): err.append('Cannot access ' + path + ' at: ' + path_val) setattr(args, path, path_val) # Check and sanitize paths for write access for path in ['output_dir', 'mini_build']: path_val = getattr(args, path, None) if path_val: path_val = c_path.normalize(path_val) try: c_path.create_dir(path_val) except Exception as e: err.append('Cannot write at: ' + path_val + '\n' ' ' + 'Error: ' + str(e)) setattr(args, path, path_val) # Raise error if any if err: if len(err) > 1: err = [(' ' + str(idx + 1) + '. ' + error) for idx, error in enumerate(err)] err = 'Please check the command line args:\n\n' + '\n'.join( err) else: err = err[0] raise RuntimeError(err)
def c_add_options(self): """Adds the command line args supported by secimage.""" # Signing individual image img_group = self.add_option_group('Signing individual image') img_group.add_option('--overrides', action='store_true', help=optparse.SUPPRESS_HELP) img_group.add_option('-i', '--image_file', metavar='<file>', help='path to the image file.') img_group.add_option( '-g', '--sign_id', metavar='<id>', help='sign id corresponding to the image_file provided.') img_group.add_option( '-p', '--chipset', metavar='<id>', help='id of the chipset corresponding to the image_file.') img_group.add_option('-c', '--config_path', metavar='<file>', help='path to the secimage config file.') img_group.add_option('--qti', '--qti_signing', action='store_true', dest="qti_signing", default=False, help=optparse.SUPPRESS_HELP) img_group.add_option('--verbatim_config', action='store_true', default=False, help=optparse.SUPPRESS_HELP) # Signing metabuild meta_group = self.add_option_group('Signing images from metabuild') meta_group.add_option( '-m', '--meta_build', metavar='<dir>', help= 'path to the meta-build to be used for obtaining the images to sign.' ) # Specifying the output location output_group = self.add_option_group('Specifying output location') output_group.add_option( '-o', '--output_dir', metavar='<dir>', help='directory to store output files. DEFAULT: "./' + DEF_SECIMAGE_OUTPUT_DIR_NAME + '"', default=DEF_SECIMAGE_OUTPUT_DIR_PATH) output_group.add_option( '-n', '--mini_build', metavar='<dir>', help='path to the minimized build to store the signed images to. ' 'This option works with the meta_build option.') # Specifying the operation operations_group = self.add_option_group( 'Operations for individual images') operations_group.add_option('-t', '--integrity_check', action='store_true', default=False, help='add hash table segment.') operations_group.add_option( '-r', '--sign_attr', action='store_true', default=False, help= 'add signing attributes to hash table segment of unsigned Secboot 3.0 image.' ) operations_group.add_option('-s', '--sign', action='store_true', default=False, help='sign the image.') operations_group.add_option('-e', '--encrypt', action='store_true', default=False, help='encrypt the image.') operations_group.add_option('--decrypt', action='store_true', default=False, help=optparse.SUPPRESS_HELP) operations_group.add_option('-a', '--validate', action='store_true', default=False, help='validate the image.') operations_group.add_option( '--no_op', action='store_true', default=False, help= 'perform no operations on individual image when adding entry to ' + multi_image_string() + ' image.') operations_group.add_option('-l', '--verify_inputs', action='store_true', default=False, help='verify the command line options.') operations_group.add_option( "--enforce_signed", action="store_true", default=False, help="raise an error if an image is unsigned.") operations_group.add_option( "--enforce_encrypted", action="store_true", default=False, help="raise an error if an image is unencrypted.") # Multi-Image Sign & Integrity image operations multi_image_group = self.add_option_group( 'Operations for ' + multi_image_string() + ' images\n' + ' (to be used when adding or updating image entries in ' + multi_image_string() + ' image)') multi_image_group.add_option('--m_gen', action='store_true', default=False, help='generate a new ' + multi_image_string() + ' image.') multi_image_group.add_option('--m_image_file', metavar='<file>', help='path to an existing ' + multi_image_string() + ' image file.') multi_image_group.add_option('--m_integrity_check', action='store_true', default=False, help='add hash table segment to ' + multi_image_string() + ' image.') multi_image_group.add_option( '--m_sign_attr', action='store_true', default=False, help='add signing attributes to hash table segment of unsigned ' + multi_image_string() + ' image.') multi_image_group.add_option('--m_sign', action='store_true', default=False, help='sign the ' + multi_image_string() + ' image.') multi_image_group.add_option('--m_encrypt', action='store_true', default=False, help='encrypt the ' + multi_image_string() + ' image.') multi_image_group.add_option('--m_decrypt', action='store_true', default=False, help=optparse.SUPPRESS_HELP) multi_image_group.add_option('--m_validate', action='store_true', default=False, help='validate the ' + multi_image_string() + ' image.') # Other options other_group = self.add_option_group('Other options') other_group.add_option( '--rch', '--root_cert_hash', metavar='<root_cert_hash>', dest="rch", type="str", action="callback", callback=self.sanitize_root_cert_hash, help= 'root cert hash to validate the signed image against. root cert hash ' 'is hex string of SHA256/SHA384 or it can be string ' + comma_separated_string(rch_string) + ' to ' 'detect if image is ' + comma_separated_string(rch_string) + ' signed. ' + comma_separated_string(rch_string, final_separator='and') + ' are only applicable for ' + AUTHORITY_QTI + ' signed images.') other_group.add_option( "--" + SERIAL_NUMBERS, metavar="<%s>" % SERIAL_NUMBERS, dest=SERIAL_NUMBERS, help= "Serial numbers of devices on which image(s) will authenticate. Serial " "numbers are space-separated 32-bit hex strings. Use 'ALL' by itself " "to enable image authentication on devices of any serial number.") other_group.add_option( "--platform_binding", metavar="<" + comma_separated_string(PLATFORM_BINDINGS) + ">", dest="platform_binding", type="str", action="callback", callback=self.sanitize_platform_binding, help= "Specifies whether image(s) should be bound to JTAG ID (msm_part), SOC HW Version " "(soc_hw_version/soc_vers), or neither. If provided, takes precedence over " "in_use_soc_hw_version value. " + PLATFORM_BINDING_INDEPENDENT + " only applies to " "Trusted Applications.") # Populate override options for tag, override in self.overrides.get_properties().items(): operations_group.add_option('--' + self.override_prefix + tag, metavar='<' + override.type_str + '_value>', help=optparse.SUPPRESS_HELP) # Populate special override options for tag, override in self.spec_overrides.get_properties().items(): operations_group.add_option('--' + self.spec_override_prefix + tag, metavar='<' + override.type_str + '_value>', help=optparse.SUPPRESS_HELP)
def _create_imageinfo(self, img_config_parser, parsegen_config, sign_id, image_path, gen_multi_image=False, src_image=None, dest_image=None, crypto_params={}, imageinfo_class=ImageInfo, verbatim_config=False, disable_serial_binding=False, platform_binding=None): """ The same dest_image object should not be used by two or more image_info objects. It results in destination image path cross contamination. For example, image_info objects A and B use the same dest_image. If A.dest_image is updated with a new output_dir, then B.dest_image is changed as well, because they are the same object and share the same attributes. """ if not gen_multi_image and sign_id not in MULTI_IMAGE_SIGN_ID.values(): # Validate the sign_id sign_id = self._get_sign_id(img_config_parser, os.path.basename(image_path), sign_id) # Get the config block for the sign id img_config_block = img_config_parser.get_config_for_sign_id( sign_id) else: try: # Get the config block for the Multi-Image Sign & Integrity image img_config_block = img_config_parser.get_config_for_sign_id( sign_id) except RuntimeError: prefix = "QTI " if sign_id == QTI_MULTI_IMAGE_SIGN_ID else "" raise RuntimeError(prefix + multi_image_string() + " image is not supported for chipset {0}". format(img_config_parser.chipset)) # Create the image info object image_info = imageinfo_class( image_path, sign_id, img_config_block, img_config_parser, parsegen_config, gen_multi_image=gen_multi_image, authority=self.authority, crypto_params=crypto_params, verbatim_config=verbatim_config, disable_serial_binding=disable_serial_binding, platform_binding=platform_binding) image_info.dest_image.image_name = image_info.src_image.image_name # Set src_image if src_image is not None: image_info.src_image = src_image image_info.image_under_operation = image_info.src_image.image_path # Set dest_image if dest_image is not None: image_info.dest_image = dest_image # Check if the dest image name should be overridden if img_config_block.output_file_name is not None: image_info.dest_image.image_name = img_config_block.output_file_name return image_info