def _post_process(self, image, pil_splitter_path, meta_build_path):
        ''' Replacement tags in postsign commands for images. '''
        TAG_OUTPUT_DIR = '$(OUTPUT_DIR)'
        TAG_PIL_SPLITTER = '$(PIL_SPLITTER)'
        TAG_IMAGE_FILE = '$(IMAGE_FILE)'
        REPL_META_PATH = '$(META_BUILD)'

        if image.pil_split:
            image_file = image.image_under_operation
            self._pil_split(image_file, os.path.splitext(image_file)[0])

        if image.post_process_commands:
            # Ensure pil splitter is available
            if pil_splitter_path.find(REPL_META_PATH) != -1:
                if not meta_build_path:
                    raise RuntimeError('Metabuild path is not available for pil splitter')
                pil_splitter_path = pil_splitter_path.replace(REPL_META_PATH, meta_build_path)

            if not c_path.validate_file(pil_splitter_path):
                raise RuntimeError('Cannot access pil splitter at: ' + pil_splitter_path)

            # Run all the commands
            for cmd in [c.strip() for c in image.post_process_commands.split()]:
                # Perform any needed replacements
                cmd = cmd.replace(TAG_OUTPUT_DIR, os.path.dirname(image.image_under_operation))
                cmd = cmd.replace(TAG_PIL_SPLITTER, pil_splitter_path)
                cmd = cmd.replace(TAG_IMAGE_FILE, image.image_under_operation)

                logger.info('Running postsign command: ' + cmd)
                err = os.system(cmd)
                logger.info('Result: ' + str(err))
 def _validate_sign(self, image, parsegen):
     if parsegen.is_signed():
         signer = Signer(image.config)
         if signer.validate(parsegen):
             logger.info('Image ' + image.image_under_operation + ' signature is valid')
         else:
             raise RuntimeError('Image ' + image.image_under_operation + ' signature is not valid')
     else:
         raise RuntimeError('Image ' + image.image_under_operation + ' is not signed')
    def chipset(self, chipset):
        # Log if the chipset is changed
        try:
            selected_chipset = self.chipset
            if selected_chipset:
                logger.note('Switching chipset from "' + selected_chipset + '" to "' + chipset + '"')
        except Exception:
            pass

        # Update the config path based on the given chipset
        config_path = self._config_dir_obj.get_chipset_config_path(chipset)
        if config_path is None:
            raise RuntimeError('Config file is not found for chipset: ' + str(chipset))
        self.config_path = config_path
        logger.info('Chipset is set to: ' + chipset)
    def sign(self, signingpackage_fname, outputdir):
        signaturepackage_binary = None
        cmds = self._getCmds(signingpackage_fname, outputdir)
        cass_server = self.cass_signer_attributes.server.host if self.cass_signer_attributes.server else "default CASS server"
        logger.info("Connecting to {0}".format(cass_server))
        output = self._executeCmds(cmds)
        logger.debug(output)
        signaturepackage_filepath = os.path.join(outputdir, self.SIGNATUREPACKPAGE_RELPATH)
        if os.path.isfile(signaturepackage_filepath):
            logger.info("Signature package retrieved from server.")
            signaturepackage_binary = c_misc.load_data_from_file(signaturepackage_filepath)

            #clean up
            path, filename = os.path.split(signaturepackage_filepath)
            shutil.rmtree(path)
        return signaturepackage_binary
    def sign(self, binary_to_sign, imageinfo, debug_dir=None):
        '''
        This function returns a SignerOutput object which has all the security assets generated
        by the signer.
        '''
        self._signer_impl.validate_inputs(imageinfo.signing_attributes, imageinfo.general_properties)

        hasher = Hasher()
        hmacParams = signerutils.get_hmac_params_from_config(imageinfo.signing_attributes)
        hash_to_sign=hasher.qcom_hmac(binary_to_sign, hmacParams)
        signer_output = self._signer_impl.sign(hash_to_sign, imageinfo, binary_to_sign, debug_dir)

        #print certificate properties
        attestation_cert_obj = Certificate(signer_output.attestation_cert)
        logger.info('\nAttestation Certificate Properties:\n' + str(attestation_cert_obj))

        return signer_output
    def _generate_signing_package(self, hash_to_sign, signing_attributes, cass_signer_attributes,
                                image_path, signingpackage_fname, binary_to_sign):

        signingpackage = SigningPackage(secimage.__version__)
        signingrequest = signingpackage.createSigningRequest("image_to_sign=%s" % image_path)

        hexbindigest = binascii.b2a_hex(hash_to_sign)
        logger.debug("Digest to sign (hexbinary)= [%s]" % hexbindigest)
        signingrequest.setDigest(hexbindigest)
        signingrequest.setCapability(cass_signer_attributes.capability)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_SIZE, "0x%.8X" % len(binary_to_sign))

        hmac_params = signerutils.get_hmac_params_from_config(signing_attributes)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_HW_ID, "0x%s" % hmac_params.msm_id_str)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_ID, signing_attributes.sw_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_MODEL_ID, signing_attributes.model_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_OEM_ID, signing_attributes.oem_id)
        if signing_attributes.debug:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_DEBUG, signing_attributes.debug)
        if signing_attributes.app_id:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_APP_ID, signing_attributes.app_id)
        if signing_attributes.crash_dump:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_CRASH_DUMP, signing_attributes.crash_dump)

        if self._is_tcg_supported(signing_attributes) is True:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_TCG_MIN, signing_attributes.tcg_min)
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_TCG_MAX, signing_attributes.tcg_max)
        else:
            #opendsp does not CASS_SIGNATTR_USE_EXP3 currently
            if signing_attributes.exponent == 3:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3, 'TRUE')
            elif signing_attributes.exponent == 65537:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3, 'FALSE')
            else:
                raise RuntimeError, "Exponent value of {0} is invalid!".format(signing_attributes.exponent)

        # Set signature algorithm to SHA256 by default
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SHA256, 'TRUE')

        pathname, fname = os.path.split(signingpackage_fname)
        c_path.create_dir(pathname)

        signingpackage.toxml()
        signingpackage.saveToFile(signingpackage_fname)
        logger.info("Signing package created. Digest = [%s]" % signingpackage.getDigest())
        return signingpackage
    def mini_build_path(self, mini_build_path):
        # Log if the mini_build_path is changed
        selected_mini_build_path = self.mini_build_path
        if selected_mini_build_path:
            logger.note('Switching mini_build_path: ' + '\n'
                        '    ' + 'from: ' + selected_mini_build_path + '\n'
                        '    ' + ' to: ' + mini_build_path)

        # Update the mini_build_path
        self._stager.mini_build_path = mini_build_path
        logger.info('Minimized Build is set to: ' + mini_build_path)

        # Clear the output dir setting
        try:
            self._stager.output_dir = ''
        except Exception:
            pass
    def config_path(self, config_path):
        # Log if the config_path is changed
        try:
            selected_config_path = self.config_path
            if selected_config_path:
                logger.note('Switching config_path: ' + '\n'
                            '    ' + 'from: ' + selected_config_path + '\n'
                            '    ' + ' to: ' + config_path)
        except Exception:
            pass

        # Update the config_path
        self._img_config_parser = ConfigParser(config_path)
        logger.info('Config path is set to: ' + config_path)

        # Reset the stager at this point
        if self._stager is not None:
            logger.note('Resetting image list due to config path change.')
            self._stager = None
    def _sign_image(self, image, parsegen):
        logger.info('Resigning signed' if parsegen.is_signed() else 'Signing'
                    ' image: ' + image.image_under_operation)

        c_path.create_debug_dir(image.dest_image.debug_dir_signer)
        signer = Signer(image.config)

        # TODO: a sanity check here
        # data_to_sign = parsegen.data_to_sign
        # if data_to_sign != parsegen.data_to_sign:
        #     raise RuntimeError('Data to sign is changing')

        sign_assets = signer.sign(parsegen.data_to_sign, image, image.dest_image.debug_dir_signer)

        # Dump any debug information
        self.dump_signer_debug_data(image, sign_assets)

        parsegen.data_signature = sign_assets.signature
        parsegen.cert_chain = sign_assets.cert_chain
    def output_dir(self, output_dir):
        # Log if the output_dir is changed
        try:
            selected_output_dir = self.output_dir
            if selected_output_dir:
                logger.note('Switching output_dir: ' + '\n'
                            '    ' + 'from: ' + selected_output_dir + '\n'
                            '    ' + ' to: ' + output_dir)
        except Exception:
            pass

        # Update the output_dir
        self._stager.output_dir = output_dir
        logger.info('Output dir is set to: ' + output_dir)

        # Clear the minimized build setting
        try:
            self._stager.mini_build_path = ''
        except Exception:
            pass
Exemple #11
0
        def _process(idx, image, sign_attr, integrity_check, sign, encrypt,
                     decrypt, val_image, val_integrity_check, val_sign,
                     val_encrypt):
            assert isinstance(image, ImageInfo)

            logger.info(
                '------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' +
                             str(total_image_count) + ': ' +
                             image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            file_logger_id = None
            image.authority = self.authority

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' +
                                       image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Set the root cert hash
                image.validation_root_cert_hash = root_cert_hash

                # Enable file logging to the directory
                file_logger_id = logger.add_file_logger(
                    c_path.join(image_output_dir, 'SecImage_log.txt'),
                    logger.verbosity)

                # Create the security policies list for this image
                security_policy_list = create_security_policy_list(image)

                # Parsegen object
                parsegen = None

                # For secure operations
                if integrity_check or sign or encrypt or decrypt:
                    parsegen = self._process_secure_operation(
                        image, progress, security_policy_list, sign_attr,
                        integrity_check, sign, encrypt, decrypt)

                # For validation
                if val_image or val_integrity_check or val_sign or val_encrypt:
                    # Bypass validation when encrypted key provide is configured as UIE server because decryption will always fail
                    if parsegen is not None and parsegen.is_encrypted(
                    ) and encrypted_key_provider_id_supported(
                            image.general_properties.UIE_key):
                        logger.warning(
                            "Skipping validation because encrypted key provider is configured as UIE server"
                        )
                    else:
                        parsegen = self._process_validation(
                            image, progress, security_policy_list, val_image,
                            val_integrity_check, val_sign, val_encrypt)

                # Print the image data
                if parsegen is not None:
                    logger.info('\n' + str(parsegen))

                # Set overall processing to true
                if not ((val_image and image.status.validate_parsegen.state
                         == StatusInfo.ERROR) or
                        (val_integrity_check
                         and image.status.validate_integrity_check.state
                         == StatusInfo.ERROR) or
                        (val_sign and image.status.validate_sign.state
                         == StatusInfo.ERROR) or
                        (val_encrypt and image.status.validate_encrypt.state
                         == StatusInfo.ERROR)):
                    image.status.overall.state = StatusInfo.SUCCESS

            except RemoteSignerNote as e:
                logger.info('NOTE: ' + str(e), color=logger.YELLOW)
            except Exception:
                logger.error(traceback.format_exc())
                logger.error(sys.exc_info()[1])
            finally:
                if file_logger_id is not None:
                    logger.removeFileLogger(file_logger_id)

            logger.info(
                '------------------------------------------------------\n')
Exemple #12
0
def print_summary(args, image_info_list):
    """Prints the summary of the actions performed by SecImage"""
    actions = []

    # Check which actions were performed
    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 not 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
    logger.info('SUMMARY:' + '\n' + 'Following actions were performed: "' +
                ', '.join(actions) + '"' + '\n' + 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):
        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)

    # TODO: put the error and image paths

    logger.info(summary_table.get_data())
Exemple #13
0
    def _process_secure_operation(self,
                                  image,
                                  progress,
                                  security_policy_list,
                                  sign_attr,
                                  i_integrity_check,
                                  i_sign,
                                  i_encrypt,
                                  i_decrypt,
                                  idx=0,
                                  prefix_override=None):
        from imageinfo import ImageInfo, StatusInfo
        # Check bounds
        if len(security_policy_list) == 0:
            raise RuntimeError('Security policy list must not be empty.')
        elif len(security_policy_list) <= idx:
            raise RuntimeError(
                'Security policy list length must be more than index.')

        # Get the current security policy
        file_type = security_policy_list[idx].file_type
        integrity_check = security_policy_list[
            idx].integrity_check and i_integrity_check
        sign = security_policy_list[idx].sign and i_sign
        encrypt = security_policy_list[idx].encrypt and i_encrypt
        decrypt = security_policy_list[idx].encrypt and i_decrypt

        # Create the encryptor object
        encdec = None
        if image.general_properties.selected_encryptor:
            c_path.create_debug_dir(image.dest_image.debug_dir_encdec)
            encdec = get_encdec(image, False)

        # Create the parsegen object
        file_type_backup = image.image_type.file_type
        encdec_backup = image.encdec
        image.image_type.file_type = file_type
        image.encdec = encdec
        try:
            parsegen = self._status_updater(self._create_parsegen_obj,
                                            image.status.parsegen, progress,
                                            True, image, False, sign,
                                            prefix_override, sign_attr)
        finally:
            image.image_type.file_type = file_type_backup
            image.encdec = encdec_backup

        # Validate the authority settings
        self.validate_authority_settings(
            self.authority, image.general_properties.secboot_version,
            image.general_properties.qti_sign,
            image.general_properties.oem_sign,
            image.general_properties.num_root_certs, encrypt)

        # Do not allow signed unencrypted elf images to be encrypted as the
        # Sign will not longer match the encrypted image's tosign
        if parsegen.file_type() == 'elf' and parsegen.is_signed(
        ) and not sign and not parsegen.is_encrypted() and encrypt:
            raise RuntimeError(
                'Cannot encrypt a signed unencrypted image without resigning '
                'as the sign no longer matches the format change.')

        # Set the security mechanisms
        parsegen.integrity_check = security_policy_list[
            idx].integrity_check and (parsegen.contains_integrity_check()
                                      or integrity_check)
        parsegen.sign = security_policy_list[idx].sign and (
            parsegen.is_signed() or sign)
        parsegen.encrypt = security_policy_list[idx].encrypt and (
            False if decrypt else (parsegen.is_encrypted() or encrypt))

        # Get blob if populating encryption parameters:
        if encrypt:
            if encdec is None:
                raise RuntimeError('Encryptor is not set')
            parsegen.encryption_params = encdec.get_encryption_parameters_blob(
            )
            # check if input image is a TA, if yes re-initialize encdec object with updated bitmap for manifest segment
            if int(image.signing_attributes.sw_id, 16) == 0xC:
                non_encrypt_segment_found, encrypted_segments_indices = self._get_encrypted_segments_index_list(
                    parsegen._elf_parsegen.phdrs)
                if non_encrypt_segment_found and len(
                        encrypted_segments_indices) > 0:
                    logger.info(
                        "Re-initializing encdec object for updated segment bitmap"
                    )
                    encdec = get_encdec(image, False,
                                        encrypted_segments_indices)
                    parsegen.encryption_params = encdec.get_encryption_parameters_blob(
                    )
                    parsegen.encdec = encdec

        elif parsegen.encryption_params and parsegen.encdec is not None:
            parsegen.encdec.update_encryption_parameters(
                parsegen.encryption_params)

        # Dump any debug data
        self.dump_parsegen_debug_data(image, parsegen)

        # If the security policy list contains more formats, call them
        if idx < len(security_policy_list) - 1:
            data = parsegen.get_wrapped_data()
            import tempfile
            tmp_fd = tempfile.NamedTemporaryFile(delete=False)
            tmp_fd.close()
            store_data_to_file(tmp_fd.name, data)

            # Backup the source path here
            src_image_dir_base = image.src_image.image_dir_base
            src_image_dir_ext = image.src_image.image_dir_ext
            src_image_name = image.src_image.image_name

            image.src_image.image_dir_base = os.path.dirname(tmp_fd.name)
            image.src_image.image_dir_ext = ''
            image.src_image.image_name = os.path.basename(tmp_fd.name)

            # Override debug dumped file prefix
            prefix_override = SecImageCore._get_prefix_override(
                prefix_override, file_type)

            try:
                data = self._process_secure_operation(
                    image, progress, security_policy_list, sign_attr,
                    i_integrity_check, i_sign, i_encrypt, i_decrypt, idx + 1,
                    prefix_override)
            finally:
                image.src_image.image_dir_base = src_image_dir_base
                image.src_image.image_dir_ext = src_image_dir_ext
                image.src_image.image_name = src_image_name

            os.remove(tmp_fd.name)

            parsegen.set_wrapped_data(data)

        # Sign the image
        if sign:
            self._status_updater(self._sign_image, image.status.sign, progress,
                                 True, image, parsegen)

        # Package and generate the output image file
        data = parsegen.get_data()
        if integrity_check:
            image.status.integrity_check.state = StatusInfo.SUCCESS
        if encrypt:
            image.status.encrypt.state = StatusInfo.SUCCESS

        if idx != 0:
            return data

        if decrypt:
            encryption_params_backup = parsegen.encryption_params
            parsegen.encryption_params = ''
            try:
                store_data_to_file(image.dest_image.decrypted_file,
                                   parsegen.get_data())
            finally:
                parsegen.encryption_params = encryption_params_backup

        else:
            store_data_to_file(image.dest_image.image_path, data)

        logger.info(('Signed ' if sign else '') +
                    ('& ' if sign and encrypt else '') +
                    ('Encrypted ' if encrypt else '') + 'image is stored at ' +
                    image.dest_image.image_path)
        image.image_under_operation = image.dest_image.image_path

        # Do any post processing
        self._status_updater(self._post_process, image.status.postprocess,
                             progress, True, image,
                             image.config.post_process.pil_splitter,
                             getattr(self._stager, '_meta_build_path', None))

        return parsegen
Exemple #14
0
    def reset_workspace(self,
                        chipset=None,
                        oem=True,
                        qc=True,
                        ui=True,
                        user=True):
        """Resets the :meth:`workspace` for the chipset that is provided.
        :meth:`config_dir` is searched for the files for the chipset. If the
        files are found in the config_dir, they are copied to the workspace,
        otherwise an exception is raised.

        :param str chipset: The chipset to reset in the workspace.
        :param bool oem: If the oem file should be updated.
        :param bool qc: If the qc file should be updated.
        :param bool ui: If the ui file should be updated.
        :param bool user: If the user file should be updated.
        :raise RuntimeError: If files for the chipset are not found in the
            the config_dir
        """
        if chipset is None:
            chipset = self.chipset

        # Look for the config files in the config_dir
        try:
            template_oem, template_qc, template_ui, template_user = self._config_dir_obj.get_chipset_config_paths(
                chipset)
        except Exception as e:
            logger.warning(
                'Template config files not found for copying to workspace for chipset: '
                + chipset + '\n'
                '    ' + 'Error: ' + str(e))
            raise

        # Create the directory in the workspace for this chipset
        self._workspace_dir_obj.create_chipset_dir(chipset)
        workspace_chipset_dir = self._workspace_dir_obj.get_chipset_dir(
            chipset)

        if not oem:
            # Copy the OEM template file
            logger.info(
                'Copying template OEM config file to workspace for chipset: ' +
                chipset)
            shutil.copy(template_oem, workspace_chipset_dir)
            logger.note('OEM config file created at: ' + workspace_chipset_dir)

        if not qc:
            # Copy the QC template file
            logger.info(
                'Copying template QC config file to workspace for chipset: ' +
                chipset)
            shutil.copy(template_qc, workspace_chipset_dir)
            logger.note('QC config file created at: ' + workspace_chipset_dir)

        if not ui:
            # Copy the UI template file
            logger.info(
                'Copying template UI config file to workspace for chipset: ' +
                chipset)
            shutil.copy(template_ui, workspace_chipset_dir)
            logger.note('UI config file created at: ' + workspace_chipset_dir)

        if not user:
            # Copy the USER template file
            logger.info(
                'Copying template USER config file to workspace for chipset: '
                + chipset)
            shutil.copy(template_user, workspace_chipset_dir)
            logger.note('USER config file created at: ' +
                        workspace_chipset_dir)
 def _validate_encrypt(self, image, parsegen):
     if parsegen.is_encrypted():
         logger.info('Image ' + image.image_under_operation + ' is encrypted')
     else:
         raise CustomError('Image ' + image.image_under_operation + ' is not encrypted')
    def _validate_tcg_raw(self, tcg_min_attest, tcg_max_attest,
                                tcg_min_ca, tcg_max_ca):
        tcg_ok = False

        if (self.config.general_properties.num_certs_in_certchain == 2) and \
            (self.config.signing.signature_format == "opendsp"):
            logger.info("2-level certificate chain is not supported for opendsp signature")
            return False

        if tcg_min_attest is not None:
            assert(isinstance(tcg_min_attest, BaseAttribute))
        if tcg_max_attest is not None:
            assert(isinstance(tcg_max_attest, BaseAttribute))
        if tcg_min_ca is not None:
            assert(isinstance(tcg_min_ca, BaseAttribute))
        if tcg_max_ca is not None:
            assert(isinstance(tcg_max_ca, BaseAttribute))

        if ((tcg_min_attest is None) and (tcg_max_attest is None) and
            (tcg_min_ca is None) and (tcg_max_ca is None)):
            # This is ok. No TCGs in attest cert.
            tcg_ok = True
            logger.debug("\nNo TCGs found in Attestation cert or CA cert. This is OK.")
        elif ((tcg_min_attest is not None) and (tcg_max_attest is not None) and
            (tcg_min_ca is None) and (tcg_max_ca is None)):
            logger.info("\nTCGs found in Attestation cert, but not in CA cert. This is invalid.")
        elif ((tcg_min_attest is None) and (tcg_max_attest is None) and
              (tcg_min_ca is not None) and (tcg_max_ca is not None)):
            logger.info("\nNo TCGs found in Attestation cert, but there are TCGs in CA cert. This is invalid.")
        elif ((tcg_min_attest is not None) and (tcg_max_attest is not None) and
              (tcg_min_ca is not None) and (tcg_max_ca is not None)):
            if (tcg_min_ca.value <= tcg_min_attest.value <=
                  tcg_max_attest.value <= tcg_max_ca.value):
                tcg_ok = True
                logger.debug("\nTCG values fall within CA constraints.")
            else:
                logger.info("\nTCG values are outside the CA constraints.")
        else:
            logger.info("\nInvalid TCG values")

        tcg_log_mesg =  "\nAttestation cert : tcg_min={0} tcg_max={1}". \
                                format(tcg_min_attest, tcg_max_attest) + \
                        "\nCA cert (allowed): tcg_min={0} tcg_max={1}\n". \
                                format(tcg_min_ca, tcg_max_ca)
        if (tcg_ok is False):
            logger.info(tcg_log_mesg)
        else:
            logger.debug(tcg_log_mesg)

        return tcg_ok
Exemple #17
0
    def create_subject_params_attest(self, in_params):

        def create_ou_field_from_hex_list(ou_num, ou_name, hex_list, remove_0x, max_num_items_in_ou):
            item_length = 0
            ou_field = str(ou_num)
            for val in hex_list:
                item_length = len(val)-2 if remove_0x else len(val)
                ou_field += " " + (val[2:] if remove_0x else val)
            # fill remainder of OU field with zeros
            zeros = (" " + "0" * item_length) * (max_num_items_in_ou - len(hex_list))
            ou_field += zeros
            ou_field += " " + ou_name
            return ou_field

        # GET SIGNING ATTRIBUTE DATA
        num_root_certs = int(self.signing_attributes.num_root_certs) if self.signing_attributes.num_root_certs is not None else None
        debug_val = int(self.signing_attributes.debug, 16) if self.signing_attributes.debug is not None else None
        debug_serials = self.signing_attributes.debug_serials.serial if self.signing_attributes.debug_serials is not None else []
        oem_id = int(self.signing_attributes.oem_id, 16) & 0xFFFF
        model_id = int(self.signing_attributes.model_id, 16) & 0xFFFF
        app_id = int(self.signing_attributes.app_id, 16) if self.signing_attributes.app_id is not None else None
        crash_dump = int(self.signing_attributes.crash_dump, 16) if self.signing_attributes.crash_dump is not None else None
        rot_en = int(self.signing_attributes.rot_en, 16) if self.signing_attributes.rot_en is not None else None
        mask_soc_hw_version = int(self.signing_attributes.mask_soc_hw_version, 16) if self.signing_attributes.mask_soc_hw_version is not None else None
        in_use_soc_hw_version = self.signing_attributes.in_use_soc_hw_version if self.signing_attributes.in_use_soc_hw_version is not None else None
        soc_vers = self.signing_attributes.soc_vers
        use_serial_number_in_signing = self.signing_attributes.use_serial_number_in_signing if self.signing_attributes.use_serial_number_in_signing is not None else None
        oem_id_independent = self.signing_attributes.oem_id_independent if self.signing_attributes.oem_id_independent is not None else None
        revocation_enablement = int(self.signing_attributes.revocation_enablement, 16) if self.signing_attributes.revocation_enablement is not None else None
        activation_enablement = int(self.signing_attributes.activation_enablement, 16) if self.signing_attributes.activation_enablement is not None else None

        if self._is_oid_supported(self.signing_attributes) is True:
            if self.validate_oid_from_config(self.certs_info.ca.cert_path, self.signing_attributes) is False:
                raise ConfigError('{0} min and max are not set correctly in configuration.' \
                                  'Signing will not continue.'.format(self.signing_attributes.object_id.name)
                                  )
            self.certs[self.ATTEST].extfile = self._generate_attestation_certificate_extensions(
                self.openssl_info.attest_ca_xts,
                self.signing_attributes.object_id.name,
                self.signing_attributes.object_id.min,
                self.signing_attributes.object_id.max)
        else:
            self.certs[self.ATTEST].extfile = self.openssl_info.attest_ca_xts

        # Get the binary to sign length
        if self.data_to_sign_len is None:
            if self.hash_to_sign is not None:
                self.data_to_sign_len = len(self.hash_to_sign)
            else:
                raise RuntimeError('Length of binary could not be computed')

        logger.info('Generating new Attestation certificate and a random key')
        hmac_params = HMAC()
        hmac_params.init_from_config(self.signing_attributes)
        certificate_ou_sw_id = '01 ' + '%.16X' % hmac_params.sw_id + ' SW_ID'
        certificate_ou_hw_id = '02 ' + '%.16X' % hmac_params.msm_id + ' HW_ID'
        certificate_ou_oem_id = '04 ' + '%0.4X' % oem_id + ' OEM_ID'
        certificate_ou_sw_size = '05 ' + '%0.8X' % self.data_to_sign_len + ' SW_SIZE'
        certificate_ou_model_id = '06 ' + '%0.4X' % model_id + ' MODEL_ID'
        certificate_hash_alg = certificate_hash_alg_map[self.signing_attributes.hash_algorithm]

        certificate_ou = [
            certificate_ou_sw_id,
            certificate_ou_hw_id,
            certificate_ou_oem_id,
            certificate_ou_sw_size,
            certificate_ou_model_id,
            certificate_hash_alg
        ]

        # Optional attributes
        if debug_val is not None:
            certificate_ou_debug_id = '03 ' + '%0.16X' % debug_val + ' DEBUG'
            certificate_ou.append(certificate_ou_debug_id)
        if app_id is not None:
            certificate_app_id = '08 ' + '%0.16X' % app_id + ' APP_ID'
            certificate_ou.append(certificate_app_id)
        if crash_dump is not None:
            certificate_crash_dump = '09 ' + '%0.16X' % crash_dump + ' CRASH_DUMP'
            certificate_ou.append(certificate_crash_dump)
        if rot_en is not None:
            certificate_rot_en = '10 ' + '%0.16X' % rot_en + ' ROT_EN'
            certificate_ou.append(certificate_rot_en)
        if mask_soc_hw_version is not None:
            certificate_mask_soc_hw_version = '12 ' + '%0.4X' % mask_soc_hw_version + ' MASK_SOC_HW_VERSION'
            certificate_ou.append(certificate_mask_soc_hw_version)
        if in_use_soc_hw_version == 1:
            certificate_in_use_soc_hw_version = '13 ' + '%0.4X' % in_use_soc_hw_version + ' IN_USE_SOC_HW_VERSION'
            certificate_ou.append(certificate_in_use_soc_hw_version)
        if use_serial_number_in_signing == 1:
            certificate_use_serial_number_in_signing = '14 ' + '%0.4X' % use_serial_number_in_signing + ' USE_SERIAL_NUMBER_IN_SIGNING'
            certificate_ou.append(certificate_use_serial_number_in_signing)
        if oem_id_independent == 1:
            certificate_oem_id_independent = '15 ' + '%0.4X' % oem_id_independent + ' OEM_ID_INDEPENDENT'
            certificate_ou.append(certificate_oem_id_independent)

        # multiple debug serial use case
        certificate_ou_sn_list = []
        for index in xrange(0, len(debug_serials), 6):
            serial_sublist = debug_serials[index: index+6]
            certificate_ou_sn_list.append(create_ou_field_from_hex_list(16, "SN", serial_sublist, True, 6))
        certificate_ou_sn_list.reverse()
        certificate_ou.extend(certificate_ou_sn_list)

        # multiple soc hw version use case
        if soc_vers:
            if self.padding != self.PAD_PSS:
                logger.warning("soc_vers should be used with RSAPSS")
            certificate_ou.append(create_ou_field_from_hex_list(11, "SOC_VERS", soc_vers, True, 10))

        # IOT MRC use case
        if num_root_certs > 1 and self.config.metadata.chipset in IOT_MRC_CHIPSETS:
            certificate_root_cert_sel = '17 ' + '%0.4X' % self.signing_attributes.mrc_index + ' ROOT_CERT_SEL'
            certificate_ou.append(certificate_root_cert_sel)
            if revocation_enablement is not None and revocation_enablement != 0:
                certificate_revocation_enablement = '18 ' + '%0.16X' % revocation_enablement + ' REVOCATION_ENABLEMENT'
                certificate_ou.append(certificate_revocation_enablement)
            if activation_enablement is not None and activation_enablement != 0:
                certificate_activation_enablement = '19 ' + '%0.16X' % activation_enablement + ' ACTIVATION_ENABLEMENT'
                certificate_ou.append(certificate_activation_enablement)

        # Handle OU property binding
        params = dict(in_params)
        if 'OU' in params.keys():
            if type(params['OU']) == list:
                for item in params['OU']:
                    certificate_ou.append(item)
            else:
                certificate_ou.append(params['OU'])

        params['OU'] = certificate_ou
        return params
    def process(self,
                verify_setup=False,
                integrity_check=False,
                sign=False,
                encrypt=False,
                decrypt=False,
                val_image=False,
                val_integrity_check=False,
                val_sign=False,
                val_encrypt=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool integrity_check: Add integrity check to the image.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already
            encrypted)
        :param bool val_image: Validate the integrity of the image against the
            config file.
        :param bool val_integrity_check: Validate the integrity check in the image.
        :param bool val_sign: Validate that the image is signed and validate the
            integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and
            validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError('Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or integrity_check or sign or encrypt or decrypt or
                val_image or val_integrity_check or val_sign or val_encrypt):
            raise RuntimeError('Please specify one or more operations to perform.')

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Start processing images
        total_images = len(self.image_info_list)
        progress = ProgressNotifier(total_images, progress_cb, PROGRESS_TOTAL_STAGES)

        for idx, image in enumerate(self.image_info_list):
            assert isinstance(image, ImageInfo)

            logger.info('------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' + str(total_images) + ': ' + image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            file_logger_id = None

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Enable file logging to the directory
                file_logger_id = logger.add_file_logger(c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity)

                # Create the security policies list for this image
                security_policy_list = create_security_policy_list(image)

                # Parsegen object
                parsegen = None

                # For secure operations
                if integrity_check or sign or encrypt or decrypt:
                    parsegen = self._process_secure_operation(image, progress, security_policy_list, integrity_check, sign, encrypt, decrypt)

                # For validation
                if val_image or val_integrity_check or val_sign or val_encrypt:
                    parsegen = self._process_validation(image, progress, security_policy_list, val_image, val_integrity_check, val_sign, val_encrypt)

                # Print the image data
                if parsegen is not None:
                    logger.info('\n' + str(parsegen))

                # Set overall processing to true
                if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or
                        (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or
                        (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or
                        (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)):
                    image.status.overall.state = StatusInfo.SUCCESS

            except Exception:
                logger.debug(traceback.format_exc())
                logger.error(sys.exc_info()[1])

            if file_logger_id is not None:
                logger.removeFileLogger(file_logger_id)

            logger.info('------------------------------------------------------\n')
        progress.complete()
Exemple #19
0
def main(args, return_isc=False):
    """Parses the command line arguments, performs any basic operations based on
    the parsed arguments and starts processing using the isc module.
    """
    # Log to file
    flids = logger.log_to_file(SECIMAGE_TOOL_NAME, args.output_dir)

    try:
        # Print the tool's launch command
        logged_args = CoreOptionParser.mask_private_args(
            sys.argv, args._c_spec_override_prefix)
        logger.info('\n\n    SecImage launched as: "' + ' '.join(logged_args) +
                    '"\n')

        # Initialize SecImageCore
        isc = SecImageCore(debug=args.debug)

        # Configure image signer
        if args.image_file or (
                args.meta_build
                and not SecImageCore.meta_supports_sign_id(args.meta_build)):
            if args.chipset:
                isc.set_chipset(args.chipset, args._c_overrides,
                                args._c_spec_overrides)
            elif args.config_path:
                isc.set_config_path(args.config_path, args._c_overrides,
                                    args._c_spec_overrides)

        if args.qti_signing:
            isc.authority = AUTHORITY_QTI

        # Set the input
        if args.image_file:
            isc.set_image_path(args.image_file, args.sign_id, args.m_gen,
                               args.m_image_file)
        elif args.meta_build:
            isc.set_meta_build_path(
                args.meta_build,
                [] if args.sign_id is None else [args.sign_id], args.m_gen)

        # Set the output
        if args.mini_build:
            isc.mini_build_path = args.mini_build
        elif args.output_dir:
            isc.output_dir = args.output_dir

        # Process the images
        isc.process(verify_setup=args.verify_inputs,
                    sign_attr=args.sign_attr,
                    integrity_check=args.integrity_check,
                    sign=args.sign,
                    encrypt=args.encrypt,
                    decrypt=args.decrypt,
                    no_op=args.no_op,
                    val_image=args.validate,
                    val_integrity_check=args.validate,
                    val_sign=args.validate,
                    val_encrypt=args.validate,
                    m_sign_attr=args.m_sign_attr,
                    m_integrity_check=args.m_integrity_check,
                    m_sign=args.m_sign,
                    m_encrypt=args.m_encrypt,
                    m_decrypt=args.m_decrypt,
                    m_val_image=args.m_validate,
                    m_val_integrity_check=args.m_validate,
                    m_val_sign=args.m_validate,
                    m_val_encrypt=args.m_validate,
                    gen_multi_image=args.m_gen,
                    root_cert_hash=args.rch)

        # Print the summary
        print_summary(args, isc.image_info_list,
                      isc.multi_image_imageinfo_dict.values())

        if return_isc:
            return isc
        else:
            return isc.image_info_list

    finally:
        # Clear all log handlers
        logger.removeFileLogger(flids)
Exemple #20
0
    def process(self,
                verify_setup=False,
                sign=False,
                encrypt=False,
                decrypt=False,
                val_image=False,
                val_sign=False,
                val_encrypt=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already
            encrypted)
        :param bool val_image: Validate the integrity of the image against the
            config file.
        :param bool val_sign: Validate that the image is signed and validate the
            integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and
            validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError(
                'Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or sign or encrypt or val_image or val_sign
                or val_encrypt or decrypt):
            raise RuntimeError(
                'Please specify one or more operations to perform.')

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Start processing images
        total_images = len(self.image_info_list)
        progress = ProgressNotifier(total_images, progress_cb,
                                    PROGRESS_TOTAL_STAGES)

        for idx, image in enumerate(self.image_info_list):
            assert isinstance(image, ImageInfo)

            logger.info(
                '------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' +
                             str(total_images) + ': ' +
                             image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' +
                                       image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Create the encryptor object
                if encrypt or decrypt or val_encrypt:
                    try:
                        c_path.create_debug_dir(
                            image.dest_image.debug_dir_encdec)
                        encdec = get_encdec(image)
                    except Exception:
                        if not val_encrypt:
                            raise
                else:
                    encdec = None

                # Create the parsegen object
                image.encdec = encdec
                parsegen = self._status_updater(self._create_parsegen_obj,
                                                image.status.parsegen, image)
                progress.push()

                # Set the security mechanisms
                parsegen.sign = parsegen.is_signed() or sign
                parsegen.encrypt = parsegen.is_encrypted() or encrypt

                # If encrypt:
                if encrypt:
                    parsegen.encryption_params = encdec.get_encryption_parameters_blob(
                    )

                # Dump any debug data
                self.dump_parsegen_debug_data(image, parsegen)

                # Sign the image
                if sign:
                    self._status_updater(self._sign_image, image.status.sign,
                                         image, parsegen)
                progress.push()

                # Package and generate the output file
                if sign or encrypt:
                    store_data_to_file(image.dest_image.image_path,
                                       parsegen.get_data())
                    if encrypt:
                        image.status.encrypt.state = StatusInfo.SUCCESS

                    logger.info(('Signed ' if sign else '') +
                                ('& ' if sign and encrypt else '') +
                                ('Encrypted ' if encrypt else '') +
                                'image is stored at ' +
                                image.dest_image.image_path)
                    image.image_under_operation = image.dest_image.image_path

                    # Do any post processing
                    self._status_updater(
                        self._post_process, image.status.postprocess, image,
                        image.config.post_process.pil_splitter,
                        getattr(self._stager, '_meta_build_path', None))
                    progress.push()

                # Print the image data
                logger.info('\n' + str(parsegen))

                # Decrypt the image
                if decrypt:
                    store_data_to_file(image.dest_image.decrypted_file,
                                       parsegen.get_data(encrypt=False))

                # Validate parsegen
                if val_image:
                    self._validate_parsegen(image, parsegen)
                progress.push()

                # Validate sign
                if val_sign:
                    self._validate_sign(image, parsegen)
                progress.push()

                # Validate encrypt
                if val_encrypt:
                    self._validate_encrypt(image, parsegen)
                progress.push()

                # Set overall processing to true
                image.status.overall.state = StatusInfo.SUCCESS

            except Exception:
                logger.debug(traceback.format_exc())
                logger.error(sys.exc_info()[1])

            logger.info(
                '------------------------------------------------------\n')
        progress.complete()
    def _generate_new_blob(self,
                           config,
                           debug_dir,
                           encrypted_segments_indices=None):
        is_enc_key_provider = False
        if self.key_service.using_encrypted_key_provider():
            # UIE_key value was set to an encrypted key provider value. ex: "encrypted_qti" or "encrypted_oem"
            logger.info(
                "Attempting to retrieve encrypted L2, encrypted L3, and clear L3 keys from encrypted key provider..."
            )
            self.l1_key = None
            self.l2_key = None
            # get the encrypted key provider
            encrypted_key_provider_class = get_encrypted_key_provider(
                self.key_service.get_encrypted_key_provider_id())
            is_enc_key_provider = True
            if encrypted_key_provider_class.is_qti():
                sa = config.signing_attributes
                encrypted_key_provider = encrypted_key_provider_class(
                    sa.UIE_capability, sa.UIE_server_url,
                    sa.UIE_server_cert_path)
            else:
                encrypted_key_provider = encrypted_key_provider_class()

            # get the encrypted keys and clear l3 key from the encrypted key provider
            self.encrypted_l2 = encrypted_key_provider.get_encrypted_l2_key()
            self.encrypted_l3 = encrypted_key_provider.get_encrypted_l3_key()
            self.l3_key = encrypted_key_provider.get_clear_l3_key()
            logger.info(
                "Encrypted L2, encrypted L3, and clear L3 keys were successfully retrieved from encrypted key provider."
            )
            logger.debug("Encrypted L2 Key: \n" + hexdump(self.encrypted_l2))
            logger.debug("Encrypted L3 Key: \n" + hexdump(self.encrypted_l3))
        elif self.key_service.get_l1_key(
        ) is not None and self.key_service.get_l2_key(
        ) is None and self.key_service.get_l3_key(
        ) is None and self.key_service.no_enc_keys_provided():
            # only l1 key is provided locally. l2 and l3 keys will be set to randomly generated values
            logger.debug(
                "Clear L1 key was provided locally but clear L2 and clear L3 keys were not. Generating random values for clear L2 and clear L3 keys..."
            )
            self.l1_key = self.key_service.get_l1_key()
            self.l2_key = KeyService.get_new_random_clear_key()
            self.l3_key = KeyService.get_new_random_clear_key()
            logger.debug("L1 Key: \n" + hexdump(self.l1_key))
            logger.debug("L2 Key: \n" + hexdump(self.l2_key))
            logger.debug("L3 Key: \n" + hexdump(self.l3_key))
            self.encrypted_l2 = None
            self.encrypted_l3 = None
        elif self.key_service.all_clear_keys_provided(
        ) and self.key_service.no_enc_keys_provided():
            # all 3 clear keys are provided locally
            logger.debug(
                "Clear L1 key, clear L2 key, and clear L3 keys were provided locally."
            )
            self.l1_key = self.key_service.get_l1_key()
            self.l2_key = self.key_service.get_l2_key()
            self.l3_key = self.key_service.get_l3_key()
            logger.debug("L1 Key: \n" + hexdump(self.l1_key))
            logger.debug("L2 Key: \n" + hexdump(self.l2_key))
            logger.debug("L3 Key: \n" + hexdump(self.l3_key))
            self.encrypted_l2 = None
            self.encrypted_l3 = None
        elif self.key_service.all_enc_keys_provided(
        ) and self.key_service.get_l3_key(
        ) is not None and self.key_service.get_l1_key(
        ) is None and self.key_service.get_l2_key() is None:
            # encrypted l2, encrypted l3, and clear l3 are provided locally
            logger.debug(
                "Encrypted L2 key, encrypted L3 key, and clear L3 keys were provided locally."
            )
            self.l1_key = None
            self.l2_key = None
            self.l3_key = self.key_service.get_l3_key()
            self.encrypted_l2 = self.key_service.get_encrypted_l2_key()
            self.encrypted_l3 = self.key_service.get_encrypted_l3_key()
            logger.debug("Encrypted L2 Key: \n" + hexdump(self.encrypted_l2))
            logger.debug("Encrypted L3 Key: \n" + hexdump(self.encrypted_l3))
            logger.debug("L3 Key: \n" + hexdump(self.l3_key))
        else:
            raise EncryptionParameters_1_0_L2_1_0.InvalidKeyComboException(
                "The found key configuration is not allowed.\n \
                        Supported configurations: \n \
                        #1 clear L1 key \n \
                        #2 clear L1, L2, and L3 key \n \
                        #3 encrypted L2, encrypted L3, and clear L3 key \n \
                        #4 specify an encrypted key provider.\n \
                        If required files are provided, ensure that the corresponding config file \n \
                        contains the correct METACONFIG tags and values.")

        encryption_params_hdr = EncryptionParamsInfoHdr_1_0()
        encryption_params_hdr.add_encryption_param_section()
        eps_hdr = EncryptionParamsSectionHdr_1_0(
            root_key_type=config.signing_attributes.UIE_root_key_type)
        eps_body = self._get_encryption_params_section_body_class()(
            self.image_id,
            l1_key=self.l1_key,
            l2_key=self.l2_key,
            l3_key=self.l3_key,
            enc_l2_key=self.encrypted_l2,
            enc_l3_key=self.encrypted_l3,
            is_enc_key_provider=is_enc_key_provider,
            debug_dir=debug_dir,
            encrypted_segments_indices=encrypted_segments_indices)

        self.l3_image_iv = eps_body.get_image_iv()

        self.encryption_params_blob = encryption_params_hdr.get_header_blob() + \
                                      eps_hdr.get_header_blob() + \
                                      eps_body.get_binary_blob()

        logger.debug("Encryption Params: \n" +
                     hexdump(self.encryption_params_blob))
        return self.encryption_params_blob, self.l1_key
Exemple #22
0
 def _print_attestation_cert_props(self, attestation_cert, parsegen=None):
     # Print certificate properties (to make tests pass and give good debug information)
     if (hasattr(parsegen, "get_hash_segment_metadata")
             and parsegen.get_hash_segment_metadata() is None):
         logger.info('\nAttestation Certificate Properties:\n' +
                     str(Certificate(attestation_cert)))
Exemple #23
0
    def generate(self):
        """Generate the secdat file based on the configs which have been setup.

        :param str secdat: the path to the secdat file to be generated.
        """
        retval_gen, reterr_gen = self._verify_generate()
        if not retval_gen:
            raise RuntimeError(reterr_gen)

        # Get the version from config file
        ucp = self._config_parser
        ucp_file_version = ucp.get_secdat_file_version()
        ucp_fuse_version = ucp.get_secdat_fuse_version()
        ucp_file_info = ucp.get_secdat_file_info()
        version_dir = self.get_version_dir(ucp_file_version)

        #--------------------------------------------------------------------------------------------------------
        # Setting input_secdat path:
        #            @ if input given as -s
        #            @ if sec.dat exists in the keyprovision_output
        #--------------------------------------------------------------------------------------------------------
        in_secdat = None

        # Checking self secdat
        if in_secdat is None:
            try:
                in_secdat = self.secdat
            except Exception:
                pass

        # Checking common secdat
        if in_secdat is None:
            common_secdat = c_path.join(self.output_dir, defines.COMMON_DIR,
                                        version_dir, defines.SEC_DAT)
            if os.path.isfile(common_secdat):
                in_secdat = common_secdat

        # Create list of output secdat
        out_secdats = []
        IO = namedtuple('IO', 'in_data out_path')

        out_secdats.append(
            IO(
                None,
                c_path.join(self.output_dir, self.FEATURE_DIR, version_dir,
                            defines.SEC_DAT)))
        out_secdats.append(
            IO(
                load_data_from_file(in_secdat) if in_secdat else None,
                c_path.join(self.output_dir, defines.COMMON_DIR, version_dir,
                            defines.SEC_DAT)))

        # Generate the secdats:
        for secdat in out_secdats:
            out_dir = os.path.dirname(secdat.out_path)
            c_path.create_dir(out_dir)
            secdat_obj = secdat_pg(self.SECDAT_SEGMENT_TYPE, secdat.in_data)
            secdat_obj.data_model = self.data_model
            secdat_obj.write(secdat.out_path, ucp_file_version,
                             ucp_fuse_version, ucp_file_info)
            dump_debug_data_model(self.data_model, out_dir, self.debug,
                                  self.TOOL_NAME)
            dump_debug_secdat(secdat_obj, out_dir, self.debug)
            logger.info('Secdat generated at: ' + secdat.out_path)

        self.secdat = c_path.join(self.output_dir, self.FEATURE_DIR,
                                  version_dir, defines.SEC_DAT)
Exemple #24
0
 def _print_attestation_cert_props(self, attestation_cert, parsegen=None):
     logger.info('\nAttestation Certificate Properties:\n' +
                 str(CertificateBase(attestation_cert)))
Exemple #25
0
    def _sign(self, hash_to_sign,
                    cert_config,
                    signing_attributes,
                    general_properties,
                    binary_to_sign):

        openssl_config_file_paths = self.config.signing.signer_attributes.local_signer_attributes.openssl_config_inputs

        self._validate_config(cert_config, general_properties, openssl_config_file_paths)

        # Obtain all the information from the signing_attributes
        if signing_attributes.debug is not None:
            debug_val = int(signing_attributes.debug, 16)
        else:
            debug_val = None
        msm_part = int(signing_attributes.msm_part, 16)
        oem_id = int(signing_attributes.oem_id, 16)
        model_id = int(signing_attributes.model_id, 16)
        num_certs_in_certchain = general_properties.num_certs_in_certchain
        app_id = int(signing_attributes.app_id, 16) if signing_attributes.app_id is not None else None
        crash_dump = int(signing_attributes.crash_dump, 16) if signing_attributes.crash_dump is not None else None

        # Create the crypto_params_dict
        self.certconfig_parser = CertConfigParser(cert_config, signing_attributes, general_properties)
        crypto_params_dict = self.certconfig_parser.get_crypto_params()

        hmac_params = signerutils.get_hmac_params_from_config(signing_attributes)

        # Create the attestation_certificate_key_pair
        attestation_certificate_key_pair = None

        root_certificate_params = crypto_params_dict['root_certificate_properties']
        root_certificate_params_is_valid, generate_new_root_certificate = self._validate_certificate_params_dict(root_certificate_params)
        if root_certificate_params_is_valid:
            if generate_new_root_certificate:
                logger.info('Generating new Root certificate and a random key')
                generated_root_key_pair = crypto_functions.gen_rsa_key_pair(general_properties.key_size, key_exponent=signing_attributes.exponent)
                root_cert, root_key_pair = crypto_functions.create_root_certficate(root_certificate_params, generated_root_key_pair, 7300, openssl_config_file_paths.openssl_configfile_path, 1)
            else:
                logger.info('Using a predefined Root certificate and a predefined key')
                logger.info('Key Used: '+ root_certificate_params['private_key_path'])
                logger.info('Certificate Used: '+ root_certificate_params['certificate_path'])
                root_cert, root_key_pair = self._get_certificate_and_key_pair_from_files(root_certificate_params)
        else:
            logger.error("Root certificate params are invalid! Please check config file.")
            raise RuntimeError("Root certificate params are invalid! Please check config file.")

        if num_certs_in_certchain > 2:
            logger.debug("Generating Attestation CA certificate, since certchain size is greater than 2")
            attestation_ca_certificate_params = crypto_params_dict['attest_ca_certificate_properties']
            attestation_ca_params_is_valid, generate_new_attestation_ca = self._validate_certificate_params_dict(attestation_ca_certificate_params)
            if attestation_ca_params_is_valid:
                if generate_new_attestation_ca:
                    logger.info('Generating new Attestation CA certificate and a random key')
                    generated_attestation_ca__key_pair = crypto_functions.gen_rsa_key_pair(general_properties.key_size, key_exponent=signing_attributes.exponent)
                    attestation_ca_certificate, attestation_ca_certificate_key_pair = crypto_functions.create_certificate(attestation_ca_certificate_params, generated_attestation_ca__key_pair, root_cert, root_key_pair, days=7300, configfile=openssl_config_file_paths.openssl_configfile_path, serial_num=1, extfile_name=openssl_config_file_paths.ca_certificate_extensions_path)
                else:
                    logger.info('Using a predefined Attestation CA certificate and a predefined key')
                    logger.info('Key Used: '+ attestation_ca_certificate_params['private_key_path'])
                    logger.info('Certificate Used: '+ attestation_ca_certificate_params['certificate_path'])
                    attestation_ca_certificate, attestation_ca_certificate_key_pair = self._get_certificate_and_key_pair_from_files(attestation_ca_certificate_params)
            else:
                logger.error("Attestation CA certificate params are invalid! Please check config file.")
                raise RuntimeError("Attestation CA certificate params are invalid! Please check config file.")

        attestation_certificate_params = crypto_params_dict['attest_certificate_properties']
        attestation_certificate_params_is_valid, generate_new_attestation_certificate = self._validate_certificate_params_dict(attestation_certificate_params)

        if attestation_certificate_params_is_valid:
            if generate_new_attestation_certificate:
                logger.info('Generating new Attestation certificate and a random key')
                certificate_ou_sw_id ="01 " + hmac_params.sw_id_str + " SW_ID"
                certificate_ou_hw_id ="02 " + hmac_params.msm_id_str + " HW_ID"
                certificate_ou_oem_id ="04 " + "%0.4X" % oem_id + " OEM_ID"
                certificate_ou_sw_size ="05 " + "%0.8X" % len(binary_to_sign) + " SW_SIZE"
                certificate_ou_model_id ="06 " + "%0.4X" % model_id + " MODEL_ID"
                certificate_hash_alg = "07 0001 SHA256"

                certificate_ou = [
                                  certificate_ou_sw_id,
                                  certificate_ou_hw_id,
                                  certificate_ou_oem_id,
                                  certificate_ou_sw_size,
                                  certificate_ou_model_id,
                                  certificate_hash_alg
                                 ]
                #Optional attributes
                if debug_val is not None:
                    certificate_ou_debug_id ="03 " + "%0.16X" % debug_val + " DEBUG"
                    certificate_ou.append(certificate_ou_debug_id)
                if app_id is not None:
                    certificate_app_id = "08 " + "%0.16X" % app_id + " APP_ID"
                    certificate_ou.append(certificate_app_id)
                if crash_dump is not None:
                    certificate_crash_dump = "09 " + "%0.16X" % crash_dump + " CRASH_DUMP"
                    certificate_ou.append(certificate_crash_dump)

                if 'OU' in attestation_certificate_params.keys():
                    if type(attestation_certificate_params['OU'])==list:
                        for item in attestation_certificate_params['OU']:
                            certificate_ou.append(item)
                    else:
                        certificate_ou.append(attestation_certificate_params['OU'])


                attestation_certificate_params['OU']=certificate_ou

                if attestation_certificate_key_pair is None:
                    attestation_certificate_key_pair = crypto_functions.gen_rsa_key_pair(key_exponent=signing_attributes.exponent, key_size_in_bits = general_properties.key_size)
                if num_certs_in_certchain > 2: #sign the attestation cert with the attestation_ca_cert
                    attestation_certificate, attestation_certificate_key_pair = crypto_functions.create_certificate(attestation_certificate_params, attestation_certificate_key_pair, attestation_ca_certificate, attestation_ca_certificate_key_pair, days=7300, configfile=openssl_config_file_paths.openssl_configfile_path, serial_num=1, extfile_name=openssl_config_file_paths.attestation_certificate_extensions_path)
                else: #sign the attestation cert with the root cert
                    attestation_certificate, attestation_certificate_key_pair = crypto_functions.create_certificate(attestation_certificate_params, attestation_certificate_key_pair, root_cert, root_key_pair, days=7300, configfile=openssl_config_file_paths.openssl_configfile_path, serial_num=1, extfile_name=openssl_config_file_paths.attestation_certificate_extensions_path)
                attestation_certificate = crypto_functions.cert_pem_to_der(attestation_certificate)

            else:           #generate_new_attestation_certificate == False
                logger.info('Using a predefined Attestation certificate and a predefined key')
                logger.info('Key Used: '+ attestation_certificate_params['private_key_path'])
                logger.info('Certificate Used: '+ attestation_certificate_params['certificate_path'])
                attestation_certificate, attestation_certificate_key_pair = self._get_certificate_and_key_pair_from_files(attestation_certificate_params)
                attestation_certificate = crypto_functions.cert_pem_to_der(attestation_certificate)

                # Since the get_hmac_params_from_certificate_chain always works with the first cert in the cert chain,
                # this function will work for a single der certificate as well.
                hmac_params = crypto_functions.get_hmacparams_from_certificate_chain(attestation_certificate)
                hasher = Hasher()
                hash_to_sign=hasher.qcom_hmac(binary_to_sign, hmac_params)

            signature = crypto_functions.encrypt_with_private_key(hash_to_sign, attestation_certificate_key_pair['private_key'])
        else:
            logger.error("Attestation certificate params are invalid! Please check config file.")
            raise RuntimeError("Attestation certificate params are invalid! Please check config file.")

        if num_certs_in_certchain > 2:
            attestation_ca_certificate = crypto_functions.cert_pem_to_der(attestation_ca_certificate)
        else:
            attestation_ca_certificate = None

        root_cert = crypto_functions.cert_pem_to_der(root_cert)

        root_cert_list = self.certconfig_parser.get_rootcerts()
        certificate_list = self._get_certificate_list(general_properties.num_root_certs,
                                                      num_certs_in_certchain,
                                                      attestation_certificate,
                                                      attestation_ca_certificate,
                                                      root_cert,
                                                      root_cert_list)

        cert_chain=crypto_functions.create_certificate_chain(certificate_list)

        signer_output = SignerOutput()
        signer_output.root_cert = root_cert
        signer_output.attestation_ca_cert = attestation_ca_certificate
        signer_output.attestation_cert = attestation_certificate
        signer_output.signature = signature
        signer_output.cert_chain = cert_chain
        signer_output.root_cert_list = root_cert_list
        signer_output.attestation_key = attestation_certificate_key_pair['private_key']

        return signer_output
Exemple #26
0
    def create_subject_params_attest(self, in_params):
        # Set exfile
        self.certs[self.ATTEST].extfile = self.openssl_info.attest_ca_xts

        # GET SIGNING ATTRIBUTE DATA
        num_root_certs = (int(self.signing_attributes.num_root_certs)
                          if self.signing_attributes.num_root_certs is not None
                          else None)
        debug_val = (int(self.signing_attributes.debug, 16)
                     if self.signing_attributes.debug is not None else None)
        oem_id = int(self.signing_attributes.oem_id, 16) & 0xFFFF
        model_id = int(self.signing_attributes.model_id, 16) & 0xFFFF
        in_use_soc_hw_version = (self.signing_attributes.in_use_soc_hw_version
                                 if
                                 self.signing_attributes.in_use_soc_hw_version
                                 is not None else None)
        use_serial_number_in_signing = (
            self.signing_attributes.use_serial_number_in_signing
            if self.signing_attributes.use_serial_number_in_signing is not None
            else None)

        # Get the binary to sign length
        if self.data_to_sign_len is None:
            if self.hash_to_sign is not None:
                self.data_to_sign_len = len(self.hash_to_sign)
            else:
                raise RuntimeError('Length of binary could not be computed')

        logger.info('Generating new Attestation certificate and a random key')
        hmac_params = HMAC()
        hmac_params.init_from_config(self.signing_attributes)
        certificate_ou_sw_id = '01 ' + '%.16X' % hmac_params.sw_id + ' SW_ID'
        certificate_ou_hw_id = '02 ' + '%.16X' % hmac_params.msm_id + ' HW_ID'
        certificate_ou_oem_id = '04 ' + '%0.4X' % oem_id + ' OEM_ID'
        certificate_ou_sw_size = '05 ' + '%0.8X' % self.data_to_sign_len + ' SW_SIZE'
        certificate_ou_model_id = '06 ' + '%0.4X' % model_id + ' MODEL_ID'
        certificate_hash_alg = self.SHA_OU_MAP[
            self.signing_attributes.hash_algorithm]

        certificate_ou = [
            certificate_ou_sw_id, certificate_ou_hw_id, certificate_ou_oem_id,
            certificate_ou_sw_size, certificate_ou_model_id,
            certificate_hash_alg
        ]

        # Optional attributes
        if debug_val is not None:
            certificate_ou_debug_id = '03 ' + '%0.16X' % debug_val + ' DEBUG'
            certificate_ou.append(certificate_ou_debug_id)
        if in_use_soc_hw_version == 1:
            certificate_in_use_soc_hw_version = '13 ' + '%0.4X' % in_use_soc_hw_version + ' IN_USE_SOC_HW_VERSION'
            certificate_ou.append(certificate_in_use_soc_hw_version)
        if use_serial_number_in_signing == 1:
            certificate_use_serial_number_in_signing = '14 ' + '%0.4X' % use_serial_number_in_signing +\
                                                       ' USE_SERIAL_NUMBER_IN_SIGNING'
            certificate_ou.append(certificate_use_serial_number_in_signing)

        # Handle OU property binding
        params = dict(in_params)
        if 'OU' in params.keys():
            if type(params['OU']) == list:
                for item in params['OU']:
                    certificate_ou.append(item)
            else:
                certificate_ou.append(params['OU'])

        # Add OU fields
        params['OU'] = certificate_ou
        logger.info("Adding OU fields to attest certificate.")

        return params
    def sign_hash(self,
                  hash_to_sign,
                  imageinfo,
                  binary_to_sign=None,
                  debug_dir=None,
                  sha_algo=None,
                  binary_to_sign_len=None):
        # Check that openssl is available
        try:
            crypto_functions.are_available([crypto_functions.MOD_OPENSSL])
        except Exception as e:
            raise RuntimeError('Cannot sign: ' + str(e))

        # abstract some of the image information
        signing_attributes = imageinfo.signing_attributes
        general_properties = imageinfo.general_properties

        # GET OPENSSL DATA
        openssl_configfile = self.openssl_info.openssl_config
        openssl_attest_ca_xts = self.openssl_info.attest_ca_xts
        openssl_ca_cert_xts = self.openssl_info.ca_cert_xts

        # GET SIGNING ATTRIBUTE DATA
        debug_val = int(signing_attributes.debug,
                        16) if signing_attributes.debug is not None else None
        oem_id = int(signing_attributes.oem_id, 16) & 0xFFFF
        model_id = int(signing_attributes.model_id, 16) & 0xFFFF
        num_certs_in_certchain = general_properties.num_certs_in_certchain
        app_id = int(signing_attributes.app_id,
                     16) if signing_attributes.app_id is not None else None
        crash_dump = int(
            signing_attributes.crash_dump,
            16) if signing_attributes.crash_dump is not None else None
        rot_en = int(signing_attributes.rot_en,
                     16) if signing_attributes.rot_en is not None else None
        mask_soc_hw_version = int(
            signing_attributes.mask_soc_hw_version,
            16) if signing_attributes.mask_soc_hw_version is not None else None
        in_use_soc_hw_version = signing_attributes.in_use_soc_hw_version if signing_attributes.in_use_soc_hw_version is not None else None
        use_serial_number_in_signing = signing_attributes.use_serial_number_in_signing if signing_attributes.use_serial_number_in_signing is not None else None

        # GET CERTIFICATE INFORMATION
        cert_dict = {}
        cert_dict['id'] = imageinfo.cert_config
        cert_dict['chip'] = self.config.metadata.chipset
        cert_dict['keysize'] = general_properties.key_size
        cert_dict['exponent'] = general_properties.exponent
        cert_dict['mrc_index'] = general_properties.mrc_index

        # Can't use imageinfo.data_prov_basepath because MockImage can't use it
        cert_dict['dp_path'] = self.config.data_provisioning.base_path

        self.cert_data_object = CertData(cert_dict)
        crypto_params_dict = self.cert_data_object.get_crypto_params()

        # Create the attestation_certificate_key_pair
        attestation_certificate_key_pair = None

        root_certificate_params = crypto_params_dict[
            'root_certificate_properties']
        root_certificate_params_is_valid, generate_new_root_certificate = self._validate_certificate_params_dict(
            root_certificate_params)
        if root_certificate_params_is_valid:
            if generate_new_root_certificate:
                logger.info('Generating new Root certificate and a random key')
                generated_root_key_pair = crypto_functions.gen_rsa_key_pair(
                    general_properties.key_size,
                    key_exponent=signing_attributes.exponent)
                root_cert, root_key_pair = crypto_functions.create_root_certficate(
                    root_certificate_params, generated_root_key_pair, 7300,
                    openssl_configfile, 1)
            else:
                logger.info(
                    'Using a predefined Root certificate and a predefined key')
                logger.info('Key Used: ' +
                            root_certificate_params['private_key_path'])
                logger.info('Certificate Used: ' +
                            root_certificate_params['certificate_path'])
                root_cert, root_key_pair = self._get_certificate_and_key_pair_from_files(
                    root_certificate_params)
        else:
            logger.error(
                "Root certificate params are invalid! Please check config file."
            )
            raise RuntimeError(
                "Root certificate params are invalid! Please check config file."
            )

        if num_certs_in_certchain > 2:
            logger.debug(
                "Generating Attestation CA certificate, since certchain size is greater than 2"
            )
            attestation_ca_certificate_params = crypto_params_dict[
                'attest_ca_certificate_properties']
            attestation_ca_params_is_valid, generate_new_attestation_ca = self._validate_certificate_params_dict(
                attestation_ca_certificate_params)
            if attestation_ca_params_is_valid:
                if generate_new_attestation_ca:
                    logger.info(
                        'Generating new Attestation CA certificate and a random key'
                    )
                    generated_attestation_ca__key_pair = crypto_functions.gen_rsa_key_pair(
                        general_properties.key_size,
                        key_exponent=signing_attributes.exponent)
                    attestation_ca_certificate, attestation_ca_certificate_key_pair = \
                        crypto_functions.create_certificate(attestation_ca_certificate_params,
                                                            generated_attestation_ca__key_pair,
                                                            root_cert,
                                                            root_key_pair,
                                                            days=7300,
                                                            configfile=openssl_configfile,
                                                            serial_num=1,
                                                            extfile_name=openssl_ca_cert_xts)
                else:
                    logger.info(
                        'Using a predefined Attestation CA certificate and a predefined key'
                    )
                    logger.info(
                        'Key Used: ' +
                        attestation_ca_certificate_params['private_key_path'])
                    logger.info(
                        'Certificate Used: ' +
                        attestation_ca_certificate_params['certificate_path'])
                    attestation_ca_certificate, attestation_ca_certificate_key_pair = self._get_certificate_and_key_pair_from_files(
                        attestation_ca_certificate_params)
            else:
                logger.error(
                    "Attestation CA certificate params are invalid! Please check config file."
                )
                raise RuntimeError(
                    "Attestation CA certificate params are invalid! Please check config file."
                )

        attestation_certificate_params = crypto_params_dict[
            'attest_certificate_properties']
        attestation_certificate_params_is_valid, generate_new_attestation_certificate = self._validate_certificate_params_dict(
            attestation_certificate_params)

        if attestation_certificate_params_is_valid:
            if generate_new_attestation_certificate:
                # TCG support
                if self._is_oid_supported(signing_attributes) is True:
                    if self.validate_oid_from_config(
                            attestation_ca_certificate_params[
                                'certificate_path'],
                            signing_attributes) is False:
                        raise ConfigError("{0} min and max are not set correctly in configuration."\
                                          "Signing will not continue.".format(signing_attributes.object_id.name)
                                          )
                    attestation_certificate_extensions_path = self._generate_attestation_certificate_extensions(
                        openssl_attest_ca_xts,
                        signing_attributes.object_id.name,
                        signing_attributes.object_id.min,
                        signing_attributes.object_id.max)
                else:
                    attestation_certificate_extensions_path = openssl_attest_ca_xts

                # Get the binary to sign length
                if binary_to_sign_len is None:
                    if binary_to_sign is not None:
                        binary_to_sign_len = len(binary_to_sign)
                    else:
                        raise RuntimeError(
                            'Length of binary could not be computed')

                logger.info(
                    'Generating new Attestation certificate and a random key')
                hmac_params = signerutils.get_hmac_params_from_config(
                    signing_attributes)
                certificate_ou_sw_id = "01 " + hmac_params.sw_id_str + " SW_ID"
                certificate_ou_hw_id = "02 " + hmac_params.msm_id_str + " HW_ID"
                certificate_ou_oem_id = "04 " + "%0.4X" % oem_id + " OEM_ID"
                certificate_ou_sw_size = "05 " + "%0.8X" % binary_to_sign_len + " SW_SIZE"
                certificate_ou_model_id = "06 " + "%0.4X" % model_id + " MODEL_ID"
                certificate_hash_alg = SHA1_OU_STRING if sha_algo == 'sha1' else SHA256_OU_STRING

                certificate_ou = [
                    certificate_ou_sw_id, certificate_ou_hw_id,
                    certificate_ou_oem_id, certificate_ou_sw_size,
                    certificate_ou_model_id, certificate_hash_alg
                ]
                # Optional attributes
                if debug_val is not None:
                    certificate_ou_debug_id = "03 " + "%0.16X" % debug_val + " DEBUG"
                    certificate_ou.append(certificate_ou_debug_id)
                if app_id is not None:
                    certificate_app_id = "08 " + "%0.16X" % app_id + " APP_ID"
                    certificate_ou.append(certificate_app_id)
                if crash_dump is not None:
                    certificate_crash_dump = "09 " + "%0.16X" % crash_dump + " CRASH_DUMP"
                    certificate_ou.append(certificate_crash_dump)
                if rot_en is not None:
                    certificate_rot_en = "10 " + "%0.16X" % rot_en + " ROT_EN"
                    certificate_ou.append(certificate_rot_en)
                if mask_soc_hw_version is not None:
                    certificate_mask_soc_hw_version = "12 " + "%0.4X" % mask_soc_hw_version + " MASK_SOC_HW_VERSION"
                    certificate_ou.append(certificate_mask_soc_hw_version)
                if in_use_soc_hw_version == 1:
                    certificate_in_use_soc_hw_version = "13 " + "%0.4X" % in_use_soc_hw_version + " IN_USE_SOC_HW_VERSION"
                    certificate_ou.append(certificate_in_use_soc_hw_version)
                if use_serial_number_in_signing is not None:
                    certificate_use_serial_number_in_signing = "14 " + "%0.4X" % use_serial_number_in_signing + " USE_SERIAL_NUMBER_IN_SIGNING"
                    certificate_ou.append(
                        certificate_use_serial_number_in_signing)

                if 'OU' in attestation_certificate_params.keys():
                    if type(attestation_certificate_params['OU']) == list:
                        for item in attestation_certificate_params['OU']:
                            certificate_ou.append(item)
                    else:
                        certificate_ou.append(
                            attestation_certificate_params['OU'])

                attestation_certificate_params['OU'] = certificate_ou

                if attestation_certificate_key_pair is None:
                    attestation_certificate_key_pair = crypto_functions.gen_rsa_key_pair(
                        key_exponent=signing_attributes.exponent,
                        key_size_in_bits=general_properties.key_size)
                if num_certs_in_certchain > 2:  # sign the attestation cert with the attestation_ca_cert
                    attestation_certificate, attestation_certificate_key_pair = \
                        crypto_functions.create_certificate(attestation_certificate_params,
                                                            attestation_certificate_key_pair,
                                                            attestation_ca_certificate,
                                                            attestation_ca_certificate_key_pair,
                                                            days=7300,
                                                            configfile=openssl_configfile,
                                                            serial_num=1,
                                                            extfile_name=attestation_certificate_extensions_path)
                else:  # sign the attestation cert with the root cert
                    attestation_certificate, attestation_certificate_key_pair = \
                        crypto_functions.create_certificate(attestation_certificate_params,
                                                            attestation_certificate_key_pair,
                                                            root_cert,
                                                            root_key_pair,
                                                            days=7300,
                                                            configfile=openssl_configfile,
                                                            serial_num=1,
                                                            extfile_name=attestation_certificate_extensions_path)
                attestation_certificate = crypto_functions.cert_pem_to_der(
                    attestation_certificate)

                # Clean temp file
                if self._is_oid_supported(signing_attributes) is True:
                    c_path.clean_file(attestation_certificate_extensions_path)

            else:  # generate_new_attestation_certificate == False
                logger.info(
                    'Using a predefined Attestation certificate and a predefined key'
                )
                logger.info('Key Used: ' +
                            attestation_certificate_params['private_key_path'])
                logger.info('Certificate Used: ' +
                            attestation_certificate_params['certificate_path'])
                attestation_certificate, attestation_certificate_key_pair = self._get_certificate_and_key_pair_from_files(
                    attestation_certificate_params)
                attestation_certificate = crypto_functions.cert_pem_to_der(
                    attestation_certificate)

                # Since the get_hmac_params_from_certificate_chain always works with the first cert in the cert chain,
                # this function will work for a single der certificate as well.
                hmac_params = crypto_functions.get_hmacparams_from_certificate_chain(
                    attestation_certificate)
                hasher = Hasher()
                hash_to_sign = hasher.qcom_hmac(binary_to_sign, hmac_params,
                                                sha_algo)

            signature = crypto_functions.encrypt_with_private_key(
                hash_to_sign, attestation_certificate_key_pair['private_key'])
        else:
            logger.error(
                "Attestation certificate params are invalid! Please check config file."
            )
            raise RuntimeError(
                "Attestation certificate params are invalid! Please check config file."
            )

        if num_certs_in_certchain > 2:
            attestation_ca_certificate = crypto_functions.cert_pem_to_der(
                attestation_ca_certificate)
        else:
            attestation_ca_certificate = None

        root_cert = crypto_functions.cert_pem_to_der(root_cert)

        root_cert_list = self.cert_data_object.get_rootcerts(
            general_properties.num_root_certs)

        certificate_list = self._get_certificate_list(
            general_properties.num_root_certs, num_certs_in_certchain,
            attestation_certificate, attestation_ca_certificate, root_cert,
            root_cert_list)

        cert_chain = crypto_functions.create_certificate_chain(
            certificate_list)

        signer_output = SignerOutput()
        signer_output.root_cert = root_cert
        signer_output.attestation_ca_cert = attestation_ca_certificate
        signer_output.attestation_cert = attestation_certificate
        signer_output.signature = signature
        signer_output.cert_chain = cert_chain
        signer_output.root_cert_list = root_cert_list
        signer_output.root_key = root_key_pair['private_key']
        # Make sure the variable is defined
        try:
            attestation_ca_certificate_key_pair
        except Exception:
            pass
        else:
            signer_output.attestation_ca_key = attestation_ca_certificate_key_pair[
                'private_key']
        signer_output.attestation_key = attestation_certificate_key_pair[
            'private_key']

        return signer_output
    def _process_secure_operation(self, image, progress, security_policy_list,
                                  i_integrity_check, i_sign, i_encrypt, i_decrypt, idx=0):
        # Check bounds
        if len(security_policy_list) == 0:
            raise RuntimeError('Security policy list must not be empty.')
        elif len(security_policy_list) <= idx:
            raise RuntimeError('Security policy list length must be more than index.')

        # Get the current security policy
        file_type = security_policy_list[idx].file_type
        integrity_check = security_policy_list[idx].integrity_check and i_integrity_check
        sign = security_policy_list[idx].sign and i_sign
        encrypt = security_policy_list[idx].encrypt and i_encrypt
        decrypt = security_policy_list[idx].encrypt and i_decrypt

        # Create the encryptor object
        encdec = None
        if encrypt or decrypt:
            c_path.create_debug_dir(image.dest_image.debug_dir_encdec)
            encdec = get_encdec(image)

        # Create the parsegen object
        file_type_backup = image.image_type.file_type
        encdec_backup = image.encdec
        image.image_type.file_type = file_type
        image.encdec = encdec
        try:
            parsegen = self._status_updater(self._create_parsegen_obj,
                                            image.status.parsegen,
                                            progress, True,
                                            image)
        finally:
            image.image_type.file_type = file_type_backup
            image.encdec = encdec_backup

        # Do not allow signed unencrypted elf images to be encrypted as the
        # Sign will not longer match the encrypted image's tosign
        if parsegen.file_type() == 'elf' and parsegen.is_signed() and not sign and not parsegen.is_encrypted() and encrypt:
            raise RuntimeError('Cannot encrypt a signed unencrypted image without resigning '
                               'as the sign no longer matches the format change.')

        # Set the security mechanisms
        parsegen.integrity_check = security_policy_list[idx].integrity_check and (parsegen.contains_integrity_check() or integrity_check)
        parsegen.sign = security_policy_list[idx].sign and (parsegen.is_signed() or sign)
        parsegen.encrypt = security_policy_list[idx].encrypt and (False if decrypt else (parsegen.is_encrypted() or encrypt))

        # If encrypt:
        if encrypt:
            parsegen.encryption_params = encdec.get_encryption_parameters_blob()

        # Dump any debug data
        self.dump_parsegen_debug_data(image, parsegen)

        # If the security policy list contains more formats, call them
        if idx < len(security_policy_list) - 1:
            data = parsegen.get_wrapped_data()
            import tempfile
            tmp_fd = tempfile.NamedTemporaryFile(delete=False)
            tmp_fd.close()
            store_data_to_file(tmp_fd.name, data)

            # Backup the source path here
            src_image_dir_base = image.src_image.image_dir_base
            src_image_dir_ext = image.src_image.image_dir_ext
            src_image_name = image.src_image.image_name

            image.src_image.image_dir_base = os.path.dirname(tmp_fd.name)
            image.src_image.image_dir_ext = ''
            image.src_image.image_name = os.path.basename(tmp_fd.name)

            try:
                data = self._process_secure_operation(image, progress, security_policy_list,
                                                      i_integrity_check, i_sign, i_encrypt, i_decrypt, idx + 1)
            finally:
                image.src_image.image_dir_base = src_image_dir_base
                image.src_image.image_dir_ext = src_image_dir_ext
                image.src_image.image_name = src_image_name

            os.remove(tmp_fd.name)

            parsegen.set_wrapped_data(data)

        # Sign the image
        if sign:
            self._status_updater(self._sign_image,
                                 image.status.sign,
                                 progress, True,
                                 image, parsegen)

        # Package and generate the output image file
        data = parsegen.get_data()
        if integrity_check:
            image.status.integrity_check.state = StatusInfo.SUCCESS
        if encrypt:
            image.status.encrypt.state = StatusInfo.SUCCESS

        if idx != 0:
            return data

        if decrypt:
            ecryption_params_backup = parsegen.encryption_params
            parsegen.encryption_params = ''
            try:
                store_data_to_file(image.dest_image.decrypted_file, parsegen.get_data())
            finally:
                parsegen.encryption_params = ecryption_params_backup

        else:
            store_data_to_file(image.dest_image.image_path, data)

        logger.info(('Signed ' if sign else '') +
                    ('& ' if sign and encrypt else '') +
                    ('Encrypted ' if encrypt else '') +
                    'image is stored at ' + image.dest_image.image_path)
        image.image_under_operation = image.dest_image.image_path

        # Do any post processing
        self._status_updater(self._post_process,
                             image.status.postprocess,
                             progress, True,
                             image, image.config.post_process.pil_splitter,
                             getattr(self._stager, '_meta_build_path', None))

        return parsegen
Exemple #29
0
def main(args, return_isc=False):
    """Parses the command line arguments, performs any basic operations based on
    the parsed arguments and starts processing using the isc module.
    """
    # Log to file
    flids = logger.log_to_file(SECIMAGE_TOOL_NAME, args.output_dir)

    try:
        # Print the tool's launch command
        logged_args = CoreOptionParser.mask_private_args(
            sys.argv, args._c_spec_override_prefix)
        logger.info('\n\n     SecImage v' + SECIMAGE_TOOL_VERSION +
                    ' launched as: "' + ' '.join(logged_args) + '"\n')

        # Initialize SecImageCore
        # When args.serial_numbers is ALL, disable all serial-binding.
        isc = SecImageCore(debug=args.debug,
                           verbatim_config=args.verbatim_config,
                           disable_serial_binding=args.serial_numbers ==
                           DISABLE_SERIAL_BINDING,
                           platform_binding=args.platform_binding)

        # Configure image signer
        if args.image_file or (
                args.meta_build
                and not SecImageCore.meta_supports_sign_id(args.meta_build)):
            if args.chipset:
                isc.set_chipset(args.chipset, args._c_overrides,
                                args._c_spec_overrides)
            elif args.config_path:
                isc.set_config_path(args.config_path, args._c_overrides,
                                    args._c_spec_overrides)

        if args.qti_signing:
            isc.authority = AUTHORITY_QTI

        # Set the input
        if args.image_file:
            isc.set_image_path(args.image_file, args.sign_id, args.m_gen,
                               args.m_image_file)
        elif args.meta_build:
            isc.set_meta_build_path(
                args.meta_build,
                [] if args.sign_id is None else [args.sign_id], args.m_gen)

        # Set the output
        if args.mini_build:
            isc.mini_build_path = args.mini_build
        elif args.output_dir:
            isc.output_dir = args.output_dir

        # Process the images
        isc.process(verify_setup=args.verify_inputs,
                    sign_attr=args.sign_attr,
                    integrity_check=args.integrity_check,
                    sign=args.sign,
                    encrypt=args.encrypt,
                    decrypt=args.decrypt,
                    no_op=args.no_op,
                    val_image=args.validate,
                    val_integrity_check=args.validate,
                    val_sign=args.validate,
                    val_encrypt=args.validate,
                    m_sign_attr=args.m_sign_attr,
                    m_integrity_check=args.m_integrity_check,
                    m_sign=args.m_sign,
                    m_encrypt=args.m_encrypt,
                    m_decrypt=args.m_decrypt,
                    m_val_image=args.m_validate,
                    m_val_integrity_check=args.m_validate,
                    m_val_sign=args.m_validate,
                    m_val_encrypt=args.m_validate,
                    gen_multi_image=args.m_gen,
                    root_cert_hash=args.rch,
                    enforce_signed=args.enforce_signed,
                    enforce_encrypted=args.enforce_encrypted)

        # Print the summary
        print_summary(args, isc.image_info_list,
                      isc.multi_image_imageinfo_dict.values())

        overall_status = [
            image.status.overall.state == StatusInfo.SUCCESS
            for image in isc.image_info_list
        ]
        multi_image_status = [
            m.status.overall.state == StatusInfo.SUCCESS
            for m in isc.multi_image_imageinfo_dict.values()
        ]
        return_code = RETURN_CODE_SUCCESS if all(overall_status + multi_image_status) else\
            RETURN_CODE_FAILURE

        if return_isc:
            return return_code, isc
        return return_code, isc.image_info_list

    finally:
        # Clear all log handlers
        logger.removeFileLogger(flids)
    def _generate_signing_package(self, hash_to_sign, signing_attributes,
                                  cass_signer_attributes, image_path,
                                  signingpackage_fname, binary_to_sign):

        signingpackage = SigningPackage(secimage.__version__)
        signingrequest = signingpackage.createSigningRequest(
            "image_to_sign=%s" % image_path)

        hexbindigest = binascii.b2a_hex(hash_to_sign)
        logger.debug("Digest to sign (hexbinary)= [%s]" % hexbindigest)
        signingrequest.setDigest(hexbindigest)
        signingrequest.setCapability(signing_attributes.cass_capability)
        sw_size = len(hash_to_sign) if binary_to_sign is None else len(
            binary_to_sign)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_SIZE,
                                           "0x%.8X" % sw_size)

        hmac_params = signerutils.get_hmac_params_from_config(
            signing_attributes)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_HW_ID,
                                           "0x%s" % hmac_params.msm_id_str)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_SW_ID,
                                           signing_attributes.sw_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_MODEL_ID,
                                           signing_attributes.model_id)
        signingrequest.setSigningAttribute(Certificate.SIGNATTR_OEM_ID,
                                           signing_attributes.oem_id)
        if signing_attributes.debug:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_DEBUG,
                                               signing_attributes.debug)
        if signing_attributes.app_id:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_APP_ID,
                                               signing_attributes.app_id)
        if signing_attributes.crash_dump:
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_CRASH_DUMP,
                                               signing_attributes.crash_dump)

        if self._is_oid_supported(signing_attributes) is True:
            attr_min, attr_max = Certificate.GetOIDAttrName(
                signing_attributes.object_id.name)
            # Min/max can be supplied by CASS server and is optional
            if signing_attributes.object_id.min:
                signingrequest.setSigningAttribute(
                    attr_min, signing_attributes.object_id.min)
            if signing_attributes.object_id.max:
                signingrequest.setSigningAttribute(
                    attr_max, signing_attributes.object_id.max)
        else:
            # opendsp does not CASS_SIGNATTR_USE_EXP3 currently
            if signing_attributes.exponent == 3:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3,
                                                   'TRUE')
            elif signing_attributes.exponent == 65537:
                signingrequest.setSigningAttribute(self.CASS_SIGNATTR_USE_EXP3,
                                                   'FALSE')
            else:
                raise RuntimeError, "Exponent value of {0} is invalid!".format(
                    signing_attributes.exponent)

        # Set signature algorithm
        if signing_attributes.hash_algorithm and signing_attributes.hash_algorithm.lower(
        ) == 'sha1':
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_SHA256,
                                               'FALSE')
        elif signing_attributes.hash_algorithm is None or signing_attributes.hash_algorithm.lower(
        ) == 'sha256':
            signingrequest.setSigningAttribute(Certificate.SIGNATTR_SHA256,
                                               'TRUE')
        else:
            raise RuntimeError, "hash algorithm value of {0} is invalid!".format(
                signing_attributes.hash_algorithm)

        pathname, fname = os.path.split(signingpackage_fname)
        c_path.create_dir(pathname)

        signingpackage.toxml()
        signingpackage.saveToFile(signingpackage_fname)
        logger.info("Signing package created.")
        logger.info("Signing package digest from Signing Package = [%s]" %
                    signingpackage.getDigest())
        return signingpackage
    def _process_secure_operation(self, image, progress, security_policy_list,
                                  i_integrity_check, i_sign, i_encrypt, i_decrypt, idx=0):
        # Check bounds
        if len(security_policy_list) == 0:
            raise RuntimeError('Security policy list must not be empty.')
        elif len(security_policy_list) <= idx:
            raise RuntimeError('Security policy list length must be more than index.')

        # Get the current security policy
        file_type = security_policy_list[idx].file_type
        integrity_check = security_policy_list[idx].integrity_check and i_integrity_check
        sign = security_policy_list[idx].sign and i_sign
        encrypt = security_policy_list[idx].encrypt and i_encrypt
        decrypt = security_policy_list[idx].encrypt and i_decrypt

        # Create the encryptor object
        encdec = None
        if encrypt or decrypt:
            c_path.create_debug_dir(image.dest_image.debug_dir_encdec)
            encdec = get_encdec(image)

        # Create the parsegen object
        file_type_backup = image.image_type.file_type
        encdec_backup = image.encdec
        image.image_type.file_type = file_type
        image.encdec = encdec
        try:
            parsegen = self._status_updater(self._create_parsegen_obj,
                                            image.status.parsegen,
                                            progress, True,
                                            image)
        finally:
            image.image_type.file_type = file_type_backup
            image.encdec = encdec_backup

        # Do not allow signed unencrypted elf images to be encrypted as the
        # Sign will not longer match the encrypted image's tosign
        if parsegen.file_type() == 'elf' and parsegen.is_signed() and not sign and not parsegen.is_encrypted() and encrypt:
            raise RuntimeError('Cannot encrypt a signed unencrypted image without resigning '
                               'as the sign no longer matches the format change.')

        # Set the security mechanisms
        parsegen.integrity_check = security_policy_list[idx].integrity_check and (parsegen.contains_integrity_check() or integrity_check)
        parsegen.sign = security_policy_list[idx].sign and (parsegen.is_signed() or sign)
        parsegen.encrypt = security_policy_list[idx].encrypt and (False if decrypt else (parsegen.is_encrypted() or encrypt))

        # If encrypt:
        if encrypt:
            parsegen.encryption_params = encdec.get_encryption_parameters_blob()

        # Dump any debug data
        self.dump_parsegen_debug_data(image, parsegen)

        # If the security policy list contains more formats, call them
        if idx < len(security_policy_list) - 1:
            data = parsegen.get_wrapped_data()
            import tempfile
            tmp_fd = tempfile.NamedTemporaryFile(delete=False)
            tmp_fd.close()
            store_data_to_file(tmp_fd.name, data)

            # Backup the source path here
            src_image_dir_base = image.src_image.image_dir_base
            src_image_dir_ext = image.src_image.image_dir_ext
            src_image_name = image.src_image.image_name

            image.src_image.image_dir_base = os.path.dirname(tmp_fd.name)
            image.src_image.image_dir_ext = ''
            image.src_image.image_name = os.path.basename(tmp_fd.name)

            try:
                data = self._process_secure_operation(image, progress, security_policy_list,
                                                      i_integrity_check, i_sign, i_encrypt, i_decrypt, idx + 1)
            finally:
                image.src_image.image_dir_base = src_image_dir_base
                image.src_image.image_dir_ext = src_image_dir_ext
                image.src_image.image_name = src_image_name

            os.remove(tmp_fd.name)

            parsegen.set_wrapped_data(data)

        # Sign the image
        if sign:
            self._status_updater(self._sign_image,
                                 image.status.sign,
                                 progress, True,
                                 image, parsegen)

        # Package and generate the output image file
        data = parsegen.get_data()
        if integrity_check:
            image.status.integrity_check.state = StatusInfo.SUCCESS
        if encrypt:
            image.status.encrypt.state = StatusInfo.SUCCESS

        if idx != 0:
            return data

        if decrypt:
            store_data_to_file(image.dest_image.decrypted_file, data)
        else:
            store_data_to_file(image.dest_image.image_path, data)

        logger.info(('Signed ' if sign else '') +
                    ('& ' if sign and encrypt else '') +
                    ('Encrypted ' if encrypt else '') +
                    'image is stored at ' + image.dest_image.image_path)
        image.image_under_operation = image.dest_image.image_path

        # Do any post processing
        self._status_updater(self._post_process,
                             image.status.postprocess,
                             progress, True,
                             image, image.config.post_process.pil_splitter,
                             getattr(self._stager, '_meta_build_path', None))

        return parsegen
Exemple #32
0
 def log_once(self, msg):
     if msg not in self.message_print_set:
         logger.info(msg)
         self.message_print_set.add(msg)
    def _validate_sign(self, dp_file, rootcerthash=None, sign_id=None):
        """Validate the given debugpolicy elf file.
        """
        # Initialize SecImageCore
        isc = SecImageCore(debug=self.debug)
        isc.config_path = self.secimage_config
        if self.authority is not None:
            isc.authority = self.authority

        # Get the supported sign_id list
        sign_id_list = isc._img_config_parser.sign_id_list

        # Validating signed images & signed image(in case of one image) for sign_ids available in sign_id list
        if sign_id is None:
            if len(dp_file) > 1:
                for sign in range(len(dp_file)):
                    logger.info(
                        '\nValidating debugpolicy signed file against ' +
                        sign_id_list[sign] + ' signature..')
                    isc.set_image_path(dp_file[sign], sign_id_list[sign])
                    isc.output_dir = os.path.dirname(dp_file[sign])
                    isc.image_info_list[0].dest_image.image_dir_ext = ''

                    # Process the signed elf
                    isc.process(val_sign=True, root_cert_hash=rootcerthash)

                    if os.path.isfile(
                            c_path.join(self.output_dir, 'SecImage_log.txt')):
                        shutil.move(
                            c_path.join(self.output_dir, 'SecImage_log.txt'),
                            c_path.join(self.output_dir,
                                        ('val_' + sign_id_list[sign] +
                                         '_secimage_log.txt')))
            else:
                for sign in range(len(sign_id_list)):
                    logger.info(
                        '\nValidating debugpolicy signed file against ' +
                        sign_id_list[sign] + ' signature..')
                    isc.set_image_path(dp_file[0], sign_id_list[sign])
                    isc.output_dir = os.path.dirname(dp_file[0])
                    isc.image_info_list[0].dest_image.image_dir_ext = ''

                    # Process the signed elf
                    isc.process(val_sign=True, root_cert_hash=rootcerthash)

                    if os.path.isfile(
                            c_path.join(self.output_dir, 'SecImage_log.txt')):
                        shutil.move(
                            c_path.join(self.output_dir, 'SecImage_log.txt'),
                            c_path.join(self.output_dir,
                                        ('val_' + sign_id_list[sign] +
                                         '_secimage_log.txt')))

        # Validating signed image for given sign_id
        else:
            if sign_id not in sign_id_list:
                raise RuntimeError('Received sign_id "' + sign_id +
                                   '" as input.' + '\n'
                                   "       Supported sign_id's are: " +
                                   str(sign_id_list))

            logger.info('\nValidating debugpolicy signed file against ' +
                        sign_id + ' signature..')
            isc.set_image_path(dp_file[0], sign_id)
            isc.output_dir = os.path.dirname(dp_file[0])
            isc.image_info_list[0].dest_image.image_dir_ext = ''

            # Process the signed elf
            isc.process(val_sign=True, root_cert_hash=rootcerthash)

            if os.path.isfile(c_path.join(self.output_dir,
                                          'SecImage_log.txt')):
                shutil.move(
                    c_path.join(self.output_dir, 'SecImage_log.txt'),
                    c_path.join(self.output_dir,
                                ('val_' + sign_id + '_secimage_log.txt')))
 def _validate_encrypt(self, image, parsegen):
     if parsegen.is_encrypted():
         logger.info('Image ' + image.image_under_operation + ' is encrypted')
     else:
         raise RuntimeError('Image ' + image.image_under_operation + ' is not encrypted')
Exemple #35
0
 def workspace(self, workspace_path):
     workspace_path = c_path.normalize(workspace_path)
     self._workspace_dir_obj = self.CONFIG_MODULE.WorkspaceDir(
         workspace_path)
     logger.info('Workspace is set to: ' + workspace_path)
    def process(self,
                verify_setup=False,
                integrity_check=False,
                sign=False,
                encrypt=False,
                decrypt=False,
                val_image=False,
                val_integrity_check=False,
                val_sign=False,
                val_encrypt=False,
                progress_cb=PROGRESS_CB_PYPASS):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object
            is correct and return. This will ignore any other params.
        :param bool integrity_check: Add integrity check to the image.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already
            encrypted)
        :param bool val_image: Validate the integrity of the image against the
            config file.
        :param bool val_integrity_check: Validate the integrity check in the image.
        :param bool val_sign: Validate that the image is signed and validate the
            integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and
            validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during
            processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...

        """
        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError('Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or integrity_check or sign or encrypt or decrypt or
                val_image or val_integrity_check or val_sign or val_encrypt):
            raise RuntimeError('Please specify one or more operations to perform.')

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Start processing images
        total_images = len(self.image_info_list)
        progress = ProgressNotifier(total_images, progress_cb, PROGRESS_TOTAL_STAGES)

        for idx, image in enumerate(self.image_info_list):
            assert isinstance(image, ImageInfo)

            logger.info('------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' + str(total_images) + ': ' + image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            file_logger_id = None

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' + image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Enable file logging to the directory
                file_logger_id = logger.add_file_logger(c_path.join(image_output_dir, 'SecImage_log.txt'), logger.verbosity)

                # Create the security policies list for this image
                security_policy_list = create_security_policy_list(image)

                # Parsegen object
                parsegen = None

                # For secure operations
                if integrity_check or sign or encrypt or decrypt:
                    parsegen = self._process_secure_operation(image, progress, security_policy_list, integrity_check, sign, encrypt, decrypt)

                # For validation
                if val_image or val_integrity_check or val_sign or val_encrypt:
                    parsegen = self._process_validation(image, progress, security_policy_list, val_image, val_integrity_check, val_sign, val_encrypt)

                # Print the image data
                if parsegen is not None:
                    logger.info('\n' + str(parsegen))

                # Set overall processing to true
                if not ((val_image and image.status.validate_parsegen.state == StatusInfo.ERROR) or
                        (val_integrity_check and image.status.validate_integrity_check.state == StatusInfo.ERROR) or
                        (val_sign and image.status.validate_sign.state == StatusInfo.ERROR) or
                        (val_encrypt and image.status.validate_encrypt.state == StatusInfo.ERROR)):
                    image.status.overall.state = StatusInfo.SUCCESS

            except Exception:
                logger.debug(traceback.format_exc())
                logger.error(sys.exc_info()[1])

            if file_logger_id is not None:
                logger.removeFileLogger(file_logger_id)

            logger.info('------------------------------------------------------\n')
        progress.complete()
Exemple #37
0
    def process(self):
        if self.args.disclaimer:
            self.disclaimer_approval()

        #disable secimage logging
        secimage.log_to_file = lambda x: x

        logger.info(
            "Signing a file may take up to 3 minutes due to network connectivity. Please wait patiently."
        )

        retValue = True
        if self.args.input_dir:
            input_files_list = c_path.find_files(self.args.input_dir,
                                                 self.FILE_FILTER,
                                                 combine=False)
            if input_files_list == []:
                logger.info(
                    "No files to be signed in the input directory: {0}".format(
                        self.args.input_dir))
                retValue = False

            failure_list = []
            for index, input_file in enumerate(input_files_list):
                input_file_path = c_path.join(self.args.input_dir, input_file)
                logger.info(OUTPUT_DELIMINATOR)
                logger.info("Processing {0}/{1}: {2}".format(
                    (index + 1), len(input_files_list), input_file_path))
                ret = self.process_file(input_file_path)
                if ret is False:
                    failure_list.append(index)
                retValue = retValue and ret

            num_success = len(input_files_list) - len(failure_list)
            logger.info(OUTPUT_DELIMINATOR)
            logger.info("{0}/{1} succeeded.".format(num_success,
                                                    len(input_files_list)))
            if len(failure_list) > 0:
                logger.info("Failures:")
                for index in failure_list:
                    logger.info("{0}.{1}".format(
                        index + 1,
                        c_path.join(self.args.input_dir,
                                    input_files_list[index])))

        else:
            logger.info(OUTPUT_DELIMINATOR)
            retValue = self.process_file()

        return retValue
    def _validate_generation(self, dp_file):
        """Validate the generation
        """
        reterr = []

        # Set the debug params
        if self.debug:
            debug_dir = c_path.join(self.output_dir, defines.DEST_DEBUG_DIR)
            debug_prefix, debug_suffix = os.path.splitext(
                os.path.basename(c_path.join(self.output_dir, 'dp.dat')))
        else:
            debug_dir, debug_prefix, debug_suffix = None, None, None

        dbgpelfparser = ParseGenDbgpElf(
            data=load_data_from_file(dp_file),
            version=self._config_parser.root.file_properties.revision,
            debug_dir=debug_dir,
            debug_prefix=debug_prefix,
            debug_suffix=debug_suffix,
            elf_class=None)

        # Validate against the debugpolicy config file
        if self._config_parser:
            if dbgpelfparser.dbgpparser.header.version != self._config_parser.root.file_properties.revision:
                reterr.append(
                    'Revision mismatch '
                    '' + 'Debugpolicy File: ' +
                    str(dbgpelfparser.dbgpparser.header.version) + '' +
                    ' Config File: ' +
                    str(self._config_parser.root.file_properties.revision))
                logger.error(reterr)
                return

            if getattr(dbgpelfparser.dbgpparser.header, 'sernum_start', None) is not None and \
                dbgpelfparser.dbgpparser.header.sernum_start != self._config_parser.root.file_properties.serial_number_start:
                reterr.append(
                    'Serial Number Start mismatch '
                    '' + ':- \nDebugpolicy File: ' +
                    str(dbgpelfparser.dbgpparser.header.sernum_start) + '' +
                    '\nConfig File: ' +
                    str(self._config_parser.root.file_properties.
                        serial_number_start))

            if getattr(dbgpelfparser.dbgpparser.header, 'sernum_end', None) is not None and \
                dbgpelfparser.dbgpparser.header.sernum_end != self._config_parser.root.file_properties.serial_number_end:
                reterr.append('Serial Number End mismatch '
                              '' + ':- \nDebugpolicy File: ' +
                              str(dbgpelfparser.dbgpparser.header.sernum_end) +
                              '' + '\nConfig File: ' +
                              str(self._config_parser.root.file_properties.
                                  serial_number_end))

            if dbgpelfparser.dbgpparser.header.flags != self._config_parser.root.file_properties.flags:
                reterr.append(
                    'Flags mismatch '
                    '' + ':- \nDebugpolicy File: ' +
                    str(dbgpelfparser.dbgpparser.header.flags) + '' +
                    '\nConfig File: ' +
                    str(self._config_parser.root.file_properties.flags))

            if self._config_parser.root.file_properties.image_bit_map is not None:
                if dbgpelfparser.dbgpparser.header.imagebit_map != self._config_parser.root.file_properties.image_bit_map:
                    reterr.append(
                        'Image Bit Map mismatch '
                        '' + ':- \nDebugpolicy File: ' +
                        str(dbgpelfparser.dbgpparser.header.imagebit_map) +
                        '' + '\nConfig File: ' +
                        str(self._config_parser.root.file_properties.
                            image_bit_map))

            if self._config_parser.root.file_properties.image_bit_map is None:
                if getattr(dbgpelfparser.dbgpparser.header, 'imagebit_map',
                           None) is not None:
                    if dbgpelfparser.dbgpparser.header.imagebit_map != 0:
                        if dbgpelfparser.dbgpparser.header.imagebit_map != self._config_parser.root.file_properties.image_bit_map:
                            reterr.append('Image Bit Map mismatch '
                                          '' + ':- \nDebugpolicy File: ' +
                                          str(dbgpelfparser.dbgpparser.header.
                                              imagebit_map) + '' +
                                          '\nConfig File: ' +
                                          str(self._config_parser.root.
                                              file_properties.image_bit_map))

            if self._config_parser.root.file_properties.image_id_list is not None:
                if len(self._config_parser.root.file_properties.image_id_list.
                       image_id) == 0:
                    for i in range(
                            len(
                                list(dbgpelfparser.dbgpparser.header.
                                     imgid_array))):
                        if list(dbgpelfparser.dbgpparser.header.imgid_array
                                )[i] != 0:
                            reterr.append(
                                'Image ID Array mismatch '
                                '' + ':- \nDebugpolicy File: ' +
                                str(dbgpelfparser.dbgpparser.header.imgid_array
                                    ) + '' + '\nConfig File: ' +
                                str(self._config_parser.root.file_properties.
                                    image_id_list.image_id +
                                    list([0] *
                                         (32 - len(self._config_parser.root.
                                                   file_properties.
                                                   image_id_list.image_id)))))
                            break
                else:
                    for i in range(
                            len(self._config_parser.root.file_properties.
                                image_id_list.image_id)):
                        if list(
                                dbgpelfparser.dbgpparser.header.imgid_array
                        )[i] != self._config_parser.root.file_properties.image_id_list.image_id[
                                i]:
                            reterr.append(
                                'Image ID Array mismatch '
                                '' + ':- \nDebugpolicy File: ' +
                                str(dbgpelfparser.dbgpparser.header.imgid_array
                                    ) + '' + '\nConfig File: ' +
                                str(self._config_parser.root.file_properties.
                                    image_id_list.image_id +
                                    list([0] *
                                         (32 - len(self._config_parser.root.
                                                   file_properties.
                                                   image_id_list.image_id)))))
                            break

            if self._config_parser.root.file_properties.image_id_list is None:
                if getattr(dbgpelfparser.dbgpparser.header, 'imgid_count',
                           None) is not None:
                    if dbgpelfparser.dbgpparser.header.imgid_count != 0:
                        reterr.append(
                            'Image ID Array mismatch '
                            '' + ':- \nDebugpolicy File: ' +
                            str(dbgpelfparser.dbgpparser.header.imgid_array) +
                            '' + '\nConfig File: ' +
                            str(self._config_parser.root.file_properties.
                                image_id_list))

            if dbgpelfparser.dbgpparser.header.rootcerthash_array[:dbgpelfparser.dbgpparser.header.rootcerthash_count] != \
                [x.lower() for x in self._config_parser.root.file_properties.root_cert_hash_list.root_cert_hash]:
                reterr.append(
                    'Root Certificate Hash Array mismatch '
                    '' + ':- \nDebugpolicy File: ' +
                    str(dbgpelfparser.dbgpparser.header.rootcerthash_array) +
                    '' + '\nConfig File: ' +
                    str(self._config_parser.root.file_properties.
                        root_cert_hash_list.root_cert_hash))

            if getattr(dbgpelfparser.dbgpparser.header, 'serial_num_array',
                       None) is not None:
                if len(self._config_parser.root.file_properties.
                       serial_num_list.serial_num) == 0:
                    reterr.append(
                        'Serial Number Array mismatch '
                        '' + ':- \nDebugpolicy File: ' +
                        str(dbgpelfparser.dbgpparser.header.serial_num_array) +
                        '' + '\nConfig File: ' +
                        str(self._config_parser.root.file_properties.
                            serial_num_list.serial_num +
                            list([0] *
                                 (200 -
                                  len(self._config_parser.root.file_properties.
                                      serial_num_list.serial_num)))))
                else:
                    for i in range(
                            len(self._config_parser.root.file_properties.
                                serial_num_list.serial_num)):
                        if list(
                                dbgpelfparser.dbgpparser.header.
                                serial_num_array
                        )[i] != self._config_parser.root.file_properties.serial_num_list.serial_num[
                                i]:
                            reterr.append(
                                'Serial Number Array mismatch '
                                '' + ':- \nDebugpolicy File: ' +
                                str(dbgpelfparser.dbgpparser.header.
                                    serial_num_array) + '' +
                                '\nConfig File: ' +
                                str(self._config_parser.root.file_properties.
                                    serial_num_list.serial_num +
                                    list([0] *
                                         (200 -
                                          len(self._config_parser.root.
                                              file_properties.serial_num_list.
                                              serial_num)))))
                            break

            if self._config_parser.root.file_properties.root_cert_hash_qti_list is not None:
                if len(self._config_parser.root.file_properties.
                       root_cert_hash_qti_list.root_cert_hash_qti) == 0:
                    for i in range(
                            len(
                                list(dbgpelfparser.dbgpparser.header.
                                     rootcerthash_qti_array))):
                        if list(dbgpelfparser.dbgpparser.header.
                                rootcerthash_qti_array)[i] != 0:
                            reterr.append(
                                'Root Certificate Hash QTI Array mismatch '
                                '' + ':- \nDebugpolicy File: ' +
                                str(dbgpelfparser.dbgpparser.header.
                                    rootcerthash_qti_array) + '' +
                                '\nConfig File: ' +
                                str(self._config_parser.root.file_properties.
                                    root_cert_hash_qti_list.root_cert_hash_qti
                                    + list([0] * (4 - len(
                                        self._config_parser.root.
                                        file_properties.root_cert_hash_qti_list
                                        .root_cert_hash_qti)))))
                            break
                else:
                    for i in range(
                            len(self._config_parser.root.file_properties.
                                root_cert_hash_qti_list.root_cert_hash_qti)):
                        if list(
                                dbgpelfparser.dbgpparser.header.
                                rootcerthash_qti_array
                        )[i].lower(
                        ) != self._config_parser.root.file_properties.root_cert_hash_qti_list.root_cert_hash_qti[
                                i].lower():
                            reterr.append(
                                'Root Certificate Hash QTI Array mismatch '
                                '' + ':- \nDebugpolicy File: ' +
                                str(dbgpelfparser.dbgpparser.header.
                                    rootcerthash_qti_array) + '' +
                                '\nConfig File: ' +
                                str(self._config_parser.root.file_properties.
                                    root_cert_hash_qti_list.root_cert_hash_qti
                                    + list([0] * (4 - len(
                                        self._config_parser.root.
                                        file_properties.root_cert_hash_qti_list
                                        .root_cert_hash_qti)))))
                            break

            if self._config_parser.root.file_properties.root_cert_hash_qti_list is None:
                if getattr(dbgpelfparser.dbgpparser.header,
                           'rootcerthash_qti_count', None) is not None:
                    if dbgpelfparser.dbgpparser.header.rootcerthash_qti_count != 0:
                        reterr.append(
                            'Root Certificate Hash QTI Array mismatch '
                            '' + ':- \nDebugpolicy File: ' +
                            str(dbgpelfparser.dbgpparser.header.
                                rootcerthash_qti_array) + '' +
                            '\nConfig File: ' +
                            str(self._config_parser.root.file_properties.
                                root_cert_hash_qti_list))

        if reterr:
            if len(reterr) > 1:
                reterr = [('  ' + str(idx + 1) + '. ' + error)
                          for idx, error in enumerate(reterr)]
                reterr = 'Following errors were found during validation:\n\n' + '\n'.join(
                    reterr)
            else:
                reterr = reterr[0]
            logger.error(reterr)

        else:
            logger.info(
                'Validation of debugpolicy file against debugpolicy config file is Successful!'
            )
    def _execute_sign(self):
        # don't execute sectools, install, or pilsplit if no policy is provided
        if self.input.build_policy is None:
            return

        # create list containing command arguments to execute Sectools
        cmds = [
            "python",
            c_path.join(SECTOOLS_DIR,
                        "sectools.py"), "secimage", "-i", self.input.source,
            "-g", self.input.sign_id, "-c", self.input.config
        ]
        if self.input.app_id:
            cmds += ["--cfg_app_id", self.input.app_id]
        if self.input.jtag_id:
            cmds += ["--cfg_msm_part", self.input.jtag_id]
        if self.input.soc_hw_version:
            cmds += ["--cfg_soc_hw_version", self.input.soc_hw_version]
            cmds += ["--cfg_in_use_soc_hw_version", "1"]
            if self.input.soc_vers:
                cmds += ["--cfg_soc_vers", self.input.soc_vers]
        if self.input.signer:
            cmds += ["--cfg_selected_signer", self.input.signer]
        if self.input.qti_sign:
            cmds += ["--qti_signing"]
        if self.input.uie_qti:
            cmds += ["--cfg_UIE_capability", self.input.uie_qti]
            cmds += ["--cfg_UIE_key", "UIE_QTI"]
        if self.input.hash_table_algo:
            cmds += [
                "--cfg_segment_hash_algorithm", self.input.hash_table_algo
            ]
        if self.input.signature_digest_algo:
            cmds += ["--cfg_hash_algorithm", self.input.signature_digest_algo]
        if self.input.num_root_certs:
            cmds += ["--cfg_num_root_certs", self.input.num_root_certs]
        if self.input.max_num_root_certs:
            cmds += ["--cfg_max_num_root_certs", self.input.max_num_root_certs]
        if self.input.selected_cert_config:
            cmds += [
                "--cfg_selected_cert_config", self.input.selected_cert_config
            ]
        if self.input.client_id:
            cmds += ["--cfg_client_id", self.input.client_id]
        if self.input.lib_id:
            cmds += ["--cfg_lib_id", self.input.lib_id]
        if self.input.image_entry:
            cmds += ["--cfg_image_entry", self.input.image_entry]

        # maintain verbosity level across sectools
        if logger.verbosity == logger.WARN:
            cmds += ["-z"]
        elif logger.verbosity == logger.ERROR:
            cmds += ["-zz"]
        elif logger.verbosity == logger.DEBUG:
            cmds += ["-v"]

        # execute Sectools for each sec_image_policy
        for policy in self.input.build_policy.sec_image_policies:
            _cmds = copy.deepcopy(cmds)
            _cmds += [policy.cmd_options]
            # set output directory based on policy
            target_base_dir = c_path.join(self.input.target_base_dir,
                                          policy.id)
            _cmds += ["-o", target_base_dir]
            try:
                logger.debug("\nExecuting Sectools...")

                # output Sectools's output as it is being generated
                process = subprocess.Popen(_cmds, stdout=subprocess.PIPE)
                for line in iter(process.stdout.readline, ''):
                    logger.info(line.rstrip())
            except Exception, e:
                logger.error("Sectools failed!")
                if is_python_27():
                    logger.debug("Python version 2.7 is supported.")
                else:
                    logger.debug("Python version 2.7 is not supported.")
                logger.error(e.message)
                raise RuntimeError(e.message)

            # install and pilsplit sectools's output file
            self._execute_install(policy)
Exemple #40
0
    def initialize(self, imageinfo, **kwargs):
        """
        This is the first method to be called in our sign() method. You can set all of the self._cert
        data here if you have all of the keypairs and the certificates already available

        If the following variables are all set, than the below methods will never be called, and you
        simply need to override this one method

        self.certs[self.ROOT].cert
        self.certs[self.CA].cert
        self.certs[self.ATTEST].cert
        self.signature

        :return None
        """
        # Call the Base Signer v2 to call DataProv
        LocalV2Signer.initialize(self, imageinfo, **kwargs)

        data_to_hash = StructDynamic(
            self.data_to_sign if self.data_to_sign else self.hash_to_sign,
            self.data_to_sign_format)
        # Call the HSM signer method
        try:
            # Call HSM signer API which provides the format of the data to sign if it is implemented
            root_cert, ca_cert, attest_cert, signature = \
                self.sign_req_data(self.signing_attributes,
                                   self.create_subject_params(self.ATTEST, self.certs[self.ATTEST].params.params),
                                   self.hash_to_sign, data_to_hash)
        except NotImplementedError:
            # Call legacy HSM signer API
            root_cert, ca_cert, attest_cert, signature = \
                self.sign_req(self.signing_attributes,
                              self.create_subject_params(self.ATTEST, self.certs[self.ATTEST].params.params),
                              self.hash_to_sign)

        # Make sure the attest and the signature are here
        if attest_cert is None or signature is None:
            raise RuntimeError(
                "Attestation Certificate or Signature are missing from hsm_signer_output"
            )

        # Set our own internal fields and let the signer continue
        if root_cert is not None:
            logger.info("HSM Signer provided a root certificate")
            self.certs[self.ROOT].cert = root_cert

        if ca_cert is not None and self.CA in self.certs:
            logger.info("HSM Signer provided a CA certificate")
            self.certs[self.CA].cert = ca_cert

        logger.info("HSM Signer provided an attest certificate")
        self.certs[self.ATTEST].cert = attest_cert

        logger.info("HSM Signer provided a signature")

        # Pad signature to size in the header depending on authority since ECDSA signatures can be of variable size
        parsegen = kwargs.get("parsegen", None)
        authority = parsegen.authority if parsegen else AUTHORITY_OEM
        try:
            padded_length = data_to_hash.sig_size if authority == AUTHORITY_OEM else data_to_hash.sig_size_qti
        except RuntimeError:
            padded_length = len(signature)
        self.signature = signature.ljust(padded_length, PAD_BYTE_0)

        # Validation
        for key, value in self.certs.items():
            if value.cert is None:
                raise RuntimeError("Certificate " + key +
                                   " is missing from HSM Signer")
Exemple #41
0
    def process(
        self,
        verify_setup=False,
        sign_attr=False,
        integrity_check=False,
        sign=False,
        encrypt=False,
        decrypt=False,
        val_image=False,
        val_integrity_check=False,
        val_sign=False,
        val_encrypt=False,
        root_cert_hash=None,
        progress_cb=PROGRESS_CB_PYPASS,
    ):
        """Performs the secure-image related operations specified from the params.

        :param bool verify_setup: Verify that the configuration of the object is correct and return. This will ignore any other params.
        :param bool sign_attr: Add signing attributes to hash segment of images.
        :param bool integrity_check: Add integrity check to the image.
        :param bool sign: Sign the images. (Re-sign if image is already signed)
        :param bool encrypt: Encrypt the images. (Re-encrypt if image is already encrypted)
        :param bool val_image: Validate the integrity of the image against the config file.
        :param bool val_integrity_check: Validate the integrity check in the image.
        :param bool val_sign: Validate that the image is signed and validate the integrity of the signing related data.
        :param bool val_encrypt: Validate that the image is encrypted and validate the integrity of the encryption related data.
        :param cb progress_cb: Callback method to get a status update during processing.

            Callback method should have this format:
            ::
                def progress_cb(status_string, progress_percent):
                    \"""
                    :param str status_string: the current status.
                    :param int progress_percent: the progress (in percent)
                    \"""
                    ...


        """
        from imageinfo import ImageInfo, StatusInfo
        from sectools.features.isc.signer.remote import RemoteSignerNote

        # Ensure that one or more image files is provided for processing
        if self._stager is None or not self.image_path_list:
            raise RuntimeError(
                'Please specify one or more images for processing')

        # Ensure the correct set of operations is provided
        if not (verify_setup or integrity_check or sign or encrypt or decrypt
                or val_image or val_integrity_check or val_sign
                or val_encrypt):
            raise RuntimeError(
                'Please specify one or more operations to perform.')

        # Print the openssl path
        version = ''
        path_info = 'is unavailable. Please run "which openssl" and "openssl version" to check openssl version info, and upgrade to required version'
        try:
            from sectools.common import crypto
            version = 'v' + '.'.join(
                tuple(str(x) for x in
                      crypto.openssl.OPENSSL_VERSION_MIN)) + ' or greater '
            path_info = 'is available at: "' + crypto.discovery_factory.get_impl(
                crypto.modules.MOD_OPENSSL) + '"'
        except Exception as e:
            pass
        logger.info('Openssl ' + version + path_info)

        if verify_setup:
            logger.note('The inputs provided (config, cmd args) are valid.')
            return

        # Start processing images
        individual_image_count = len(self.image_info_list)
        total_image_count = individual_image_count
        progress = ProgressNotifier(total_image_count, progress_cb,
                                    PROGRESS_TOTAL_STAGES)

        def _process(idx, image, sign_attr, integrity_check, sign, encrypt,
                     decrypt, val_image, val_integrity_check, val_sign,
                     val_encrypt):
            assert isinstance(image, ImageInfo)

            logger.info(
                '------------------------------------------------------')
            status_string = ('Processing ' + str(idx + 1) + '/' +
                             str(total_image_count) + ': ' +
                             image.image_under_operation)
            logger.info(status_string + '\n')

            # Send a progress notification to the toplevel
            progress.status = status_string
            progress.cur = idx
            progress.cur_stage = 0

            file_logger_id = None
            image.authority = self.authority

            try:
                # Create the required directory structure for this image
                image_output_dir = image.dest_image.image_dir
                try:
                    c_path.create_dir(image_output_dir)
                except Exception as e:
                    raise RuntimeError('Could not create output directory: ' +
                                       image_output_dir + '\n'
                                       '    ' + 'Error: ' + str(e))

                # Enable/Disable debug
                image.dest_image.debug_enable = self.debug
                c_path.create_debug_dir(image.dest_image.debug_dir)

                # Set the root cert hash
                image.validation_root_cert_hash = root_cert_hash

                # Enable file logging to the directory
                file_logger_id = logger.add_file_logger(
                    c_path.join(image_output_dir, 'SecImage_log.txt'),
                    logger.verbosity)

                # Create the security policies list for this image
                security_policy_list = create_security_policy_list(image)

                # Parsegen object
                parsegen = None

                # For secure operations
                if integrity_check or sign or encrypt or decrypt:
                    parsegen = self._process_secure_operation(
                        image, progress, security_policy_list, sign_attr,
                        integrity_check, sign, encrypt, decrypt)

                # For validation
                if val_image or val_integrity_check or val_sign or val_encrypt:
                    # Bypass validation when encrypted key provide is configured as UIE server because decryption will always fail
                    if parsegen is not None and parsegen.is_encrypted(
                    ) and encrypted_key_provider_id_supported(
                            image.general_properties.UIE_key):
                        logger.warning(
                            "Skipping validation because encrypted key provider is configured as UIE server"
                        )
                    else:
                        parsegen = self._process_validation(
                            image, progress, security_policy_list, val_image,
                            val_integrity_check, val_sign, val_encrypt)

                # Print the image data
                if parsegen is not None:
                    logger.info('\n' + str(parsegen))

                # Set overall processing to true
                if not ((val_image and image.status.validate_parsegen.state
                         == StatusInfo.ERROR) or
                        (val_integrity_check
                         and image.status.validate_integrity_check.state
                         == StatusInfo.ERROR) or
                        (val_sign and image.status.validate_sign.state
                         == StatusInfo.ERROR) or
                        (val_encrypt and image.status.validate_encrypt.state
                         == StatusInfo.ERROR)):
                    image.status.overall.state = StatusInfo.SUCCESS

            except RemoteSignerNote as e:
                logger.info('NOTE: ' + str(e), color=logger.YELLOW)
            except Exception:
                logger.error(traceback.format_exc())
                logger.error(sys.exc_info()[1])
            finally:
                if file_logger_id is not None:
                    logger.removeFileLogger(file_logger_id)

            logger.info(
                '------------------------------------------------------\n')

        for idx, image in enumerate(self.image_info_list):
            _process(idx, image, sign_attr, integrity_check, sign, encrypt,
                     decrypt, val_image, val_integrity_check, val_sign,
                     val_encrypt)

        progress.complete()
    def _process_secure_operation(self, image, progress, security_policy_list,
                                  i_integrity_check, i_sign, idx=0, parsegens=None):
        # Check bounds
        if len(security_policy_list) == 0:
            raise RuntimeError('Security policy list must not be empty.')
        elif len(security_policy_list) <= idx:
            raise RuntimeError('Security policy list length must be more than index.')

        # Get the current security policy
        file_type = security_policy_list[idx].file_type
        integrity_check = security_policy_list[idx].integrity_check and i_integrity_check
        sign = security_policy_list[idx].sign and i_sign

        # Create the parsegen object
        file_type_backup = image.image_type.file_type
        image.image_type.file_type = file_type
        try:
            parsegen = self._status_updater(self._create_parsegen_obj,
                                            image.status.parsegen,
                                            progress,
                                            True,
                                            image,
                                            validating=False,
                                            signing=sign,
                                            parsegens=parsegens)
        finally:
            image.image_type.file_type = file_type_backup

        # Set the security mechanisms
        parsegen.integrity_check = security_policy_list[idx].integrity_check and (parsegen.contains_integrity_check() or integrity_check)
        parsegen.sign = security_policy_list[idx].sign and (parsegen.is_signed() or sign)

        # Dump any debug data
        self.dump_parsegen_debug_data(image, parsegen)

        # If the security policy list contains more formats, call them
        if idx < len(security_policy_list) - 1:
            data = parsegen.get_wrapped_data()
            tmp_fd = tempfile.NamedTemporaryFile(delete=False)
            tmp_fd.close()
            store_data_to_file(tmp_fd.name, data)

            # Backup the source path here
            src_image_dir_base = image.src_image.image_dir_base
            src_image_dir_ext = image.src_image.image_dir_ext
            src_image_name = image.src_image.image_name

            image.src_image.image_dir_base = os.path.dirname(tmp_fd.name)
            image.src_image.image_dir_ext = ''
            image.src_image.image_name = os.path.basename(tmp_fd.name)

            try:
                data = self._process_secure_operation(image, progress, security_policy_list,
                                                      i_integrity_check, i_sign, idx=idx + 1)
            finally:
                image.src_image.image_dir_base = src_image_dir_base
                image.src_image.image_dir_ext = src_image_dir_ext
                image.src_image.image_name = src_image_name

            os.remove(tmp_fd.name)

            parsegen.set_wrapped_data(data)

        # Sign the image
        if sign:
            self._status_updater(self._sign_image,
                                 image.status.sign,
                                 progress, True,
                                 image, parsegen)

        # Package and generate the output image file
        data = parsegen.get_data()
        if integrity_check:
            image.status.integrity_check.state = StatusInfo.SUCCESS

        if idx != 0:
            return data

        store_data_to_file(image.dest_image.image_path, data)

        logger.info(('Signed ' if sign else '') +
                    'image is stored at ' + image.dest_image.image_path,
                    color=logger.GREEN)
        image.image_under_operation = image.dest_image.image_path

        return parsegen
Exemple #43
0
 def logging_state_info(self, msg):
     logger.info(msg)
     if self.state:
         self.state += '\n' + msg
     else:
         self.state = '\n' + msg
    def _sign(self, hash_to_sign,
                    cert_config,
                    signing_attributes,
                    general_properties,
                    binary_to_sign):

        openssl_config_file_paths = self.config.signing.signer_attributes.local_signer_attributes.openssl_config_inputs

        self._validate_config(cert_config, general_properties, openssl_config_file_paths)

        # Obtain all the information from the signing_attributes

        debug_val = int(signing_attributes.debug, 16) if signing_attributes.debug is not None else None
        msm_part = int(signing_attributes.msm_part, 16)
        oem_id = int(signing_attributes.oem_id, 16)
        model_id = int(signing_attributes.model_id, 16)
        num_certs_in_certchain = general_properties.num_certs_in_certchain
        app_id = int(signing_attributes.app_id, 16) if signing_attributes.app_id is not None else None
        crash_dump = int(signing_attributes.crash_dump, 16) if signing_attributes.crash_dump is not None else None
        rot_en = int(signing_attributes.rot_en, 16) if signing_attributes.rot_en is not None else None

        # Create the crypto_params_dict
        self.certconfig_parser = CertConfigParser(cert_config, signing_attributes, general_properties)
        crypto_params_dict = self.certconfig_parser.get_crypto_params()

        hmac_params = signerutils.get_hmac_params_from_config(signing_attributes)

        # Create the attestation_certificate_key_pair
        attestation_certificate_key_pair = None

        root_certificate_params = crypto_params_dict['root_certificate_properties']
        root_certificate_params_is_valid, generate_new_root_certificate = self._validate_certificate_params_dict(root_certificate_params)
        if root_certificate_params_is_valid:
            if generate_new_root_certificate:
                logger.info('Generating new Root certificate and a random key')
                generated_root_key_pair = crypto_functions.gen_rsa_key_pair(general_properties.key_size, key_exponent=signing_attributes.exponent)
                root_cert, root_key_pair = crypto_functions.create_root_certficate(root_certificate_params, generated_root_key_pair, 7300, openssl_config_file_paths.openssl_configfile_path, 1)
            else:
                logger.info('Using a predefined Root certificate and a predefined key')
                logger.info('Key Used: '+ root_certificate_params['private_key_path'])
                logger.info('Certificate Used: '+ root_certificate_params['certificate_path'])
                root_cert, root_key_pair = self._get_certificate_and_key_pair_from_files(root_certificate_params)
        else:
            logger.error("Root certificate params are invalid! Please check config file.")
            raise RuntimeError("Root certificate params are invalid! Please check config file.")

        if num_certs_in_certchain > 2:
            logger.debug("Generating Attestation CA certificate, since certchain size is greater than 2")
            attestation_ca_certificate_params = crypto_params_dict['attest_ca_certificate_properties']
            attestation_ca_params_is_valid, generate_new_attestation_ca = self._validate_certificate_params_dict(attestation_ca_certificate_params)
            if attestation_ca_params_is_valid:
                if generate_new_attestation_ca:
                    logger.info('Generating new Attestation CA certificate and a random key')
                    generated_attestation_ca__key_pair = crypto_functions.gen_rsa_key_pair(general_properties.key_size, key_exponent=signing_attributes.exponent)
                    attestation_ca_certificate, attestation_ca_certificate_key_pair = \
                        crypto_functions.create_certificate(attestation_ca_certificate_params,
                                                            generated_attestation_ca__key_pair,
                                                            root_cert,
                                                            root_key_pair,
                                                            days=7300,
                                                            configfile=openssl_config_file_paths.openssl_configfile_path,
                                                            serial_num=1,
                                                            extfile_name=openssl_config_file_paths.ca_certificate_extensions_path)
                else:
                    logger.info('Using a predefined Attestation CA certificate and a predefined key')
                    logger.info('Key Used: '+ attestation_ca_certificate_params['private_key_path'])
                    logger.info('Certificate Used: '+ attestation_ca_certificate_params['certificate_path'])
                    attestation_ca_certificate, attestation_ca_certificate_key_pair = self._get_certificate_and_key_pair_from_files(attestation_ca_certificate_params)
            else:
                logger.error("Attestation CA certificate params are invalid! Please check config file.")
                raise RuntimeError("Attestation CA certificate params are invalid! Please check config file.")

        attestation_certificate_params = crypto_params_dict['attest_certificate_properties']
        attestation_certificate_params_is_valid, generate_new_attestation_certificate = self._validate_certificate_params_dict(attestation_certificate_params)

        if attestation_certificate_params_is_valid:
            if generate_new_attestation_certificate:
                #TCG support
                if self._is_tcg_supported(signing_attributes) is True:
                    if self.validate_tcg_from_config(attestation_ca_certificate_params['certificate_path'], signing_attributes) is False:
                        raise ConfigError("tcg_min and tcg_max are not set correctly in configuration."\
                                          "Signing will not continue."
                                          )
                    attestation_certificate_extensions_path = self._generate_attestation_certificate_extensions(
                                                                    openssl_config_file_paths.attestation_certificate_extensions_path,
                                                                    signing_attributes.tcg_min,
                                                                    signing_attributes.tcg_max)
                else:
                    attestation_certificate_extensions_path = openssl_config_file_paths.attestation_certificate_extensions_path


                logger.info('Generating new Attestation certificate and a random key')
                certificate_ou_sw_id ="01 " + hmac_params.sw_id_str + " SW_ID"
                certificate_ou_hw_id ="02 " + hmac_params.msm_id_str + " HW_ID"
                certificate_ou_oem_id ="04 " + "%0.4X" % oem_id + " OEM_ID"
                certificate_ou_sw_size ="05 " + "%0.8X" % len(binary_to_sign) + " SW_SIZE"
                certificate_ou_model_id ="06 " + "%0.4X" % model_id + " MODEL_ID"
                certificate_hash_alg = "07 0001 SHA256"

                certificate_ou = [
                                  certificate_ou_sw_id,
                                  certificate_ou_hw_id,
                                  certificate_ou_oem_id,
                                  certificate_ou_sw_size,
                                  certificate_ou_model_id,
                                  certificate_hash_alg
                                 ]
                #Optional attributes
                if debug_val is not None:
                    certificate_ou_debug_id ="03 " + "%0.16X" % debug_val + " DEBUG"
                    certificate_ou.append(certificate_ou_debug_id)
                if app_id is not None:
                    certificate_app_id = "08 " + "%0.16X" % app_id + " APP_ID"
                    certificate_ou.append(certificate_app_id)
                if crash_dump is not None:
                    certificate_crash_dump = "09 " + "%0.16X" % crash_dump + " CRASH_DUMP"
                    certificate_ou.append(certificate_crash_dump)
                if rot_en is not None:
                    certificate_rot_en = "10 " + "%0.16X" % rot_en + " ROT_EN"
                    certificate_ou.append(certificate_rot_en)

                if 'OU' in attestation_certificate_params.keys():
                    if type(attestation_certificate_params['OU'])==list:
                        for item in attestation_certificate_params['OU']:
                            certificate_ou.append(item)
                    else:
                        certificate_ou.append(attestation_certificate_params['OU'])

                attestation_certificate_params['OU']=certificate_ou

                if attestation_certificate_key_pair is None:
                    attestation_certificate_key_pair = crypto_functions.gen_rsa_key_pair(key_exponent=signing_attributes.exponent,
                                                                                         key_size_in_bits = general_properties.key_size)
                if num_certs_in_certchain > 2: #sign the attestation cert with the attestation_ca_cert
                    attestation_certificate, attestation_certificate_key_pair = \
                        crypto_functions.create_certificate(attestation_certificate_params,
                                                            attestation_certificate_key_pair,
                                                            attestation_ca_certificate,
                                                            attestation_ca_certificate_key_pair,
                                                            days=7300,
                                                            configfile=openssl_config_file_paths.openssl_configfile_path,
                                                            serial_num=1,
                                                            extfile_name=attestation_certificate_extensions_path)
                else: #sign the attestation cert with the root cert
                    attestation_certificate, attestation_certificate_key_pair = \
                        crypto_functions.create_certificate(attestation_certificate_params,
                                                            attestation_certificate_key_pair,
                                                            root_cert,
                                                            root_key_pair,
                                                            days=7300,
                                                            configfile=openssl_config_file_paths.openssl_configfile_path,
                                                            serial_num=1,
                                                            extfile_name=attestation_certificate_extensions_path)
                attestation_certificate = crypto_functions.cert_pem_to_der(attestation_certificate)

                #Clean temp file
                if self._is_tcg_supported(signing_attributes) is True:
                    c_path.clean_file(attestation_certificate_extensions_path)


            else:           #generate_new_attestation_certificate == False
                logger.info('Using a predefined Attestation certificate and a predefined key')
                logger.info('Key Used: '+ attestation_certificate_params['private_key_path'])
                logger.info('Certificate Used: '+ attestation_certificate_params['certificate_path'])
                attestation_certificate, attestation_certificate_key_pair = self._get_certificate_and_key_pair_from_files(attestation_certificate_params)
                attestation_certificate = crypto_functions.cert_pem_to_der(attestation_certificate)

                # Since the get_hmac_params_from_certificate_chain always works with the first cert in the cert chain,
                # this function will work for a single der certificate as well.
                hmac_params = crypto_functions.get_hmacparams_from_certificate_chain(attestation_certificate)
                hasher = Hasher()
                hash_to_sign=hasher.qcom_hmac(binary_to_sign, hmac_params)

            signature = crypto_functions.encrypt_with_private_key(hash_to_sign, attestation_certificate_key_pair['private_key'])
        else:
            logger.error("Attestation certificate params are invalid! Please check config file.")
            raise RuntimeError("Attestation certificate params are invalid! Please check config file.")

        if num_certs_in_certchain > 2:
            attestation_ca_certificate = crypto_functions.cert_pem_to_der(attestation_ca_certificate)
        else:
            attestation_ca_certificate = None

        root_cert = crypto_functions.cert_pem_to_der(root_cert)

        root_cert_list = self.certconfig_parser.get_rootcerts()
        certificate_list = self._get_certificate_list(general_properties.num_root_certs,
                                                      num_certs_in_certchain,
                                                      attestation_certificate,
                                                      attestation_ca_certificate,
                                                      root_cert,
                                                      root_cert_list)

        cert_chain=crypto_functions.create_certificate_chain(certificate_list)

        signer_output = SignerOutput()
        signer_output.root_cert = root_cert
        signer_output.attestation_ca_cert = attestation_ca_certificate
        signer_output.attestation_cert = attestation_certificate
        signer_output.signature = signature
        signer_output.cert_chain = cert_chain
        signer_output.root_cert_list = root_cert_list
        signer_output.attestation_key = attestation_certificate_key_pair['private_key']

        return signer_output
    def sign(self, dp_file, sign_id=None):
        """Sign the given debugpolicy elf file.
        """

        try:
            self.input_file_list.pop()
        except:
            pass

        # Initialize SecImageCore
        isc = SecImageCore(debug=self.debug)
        isc.config_path = self.secimage_config
        if self.authority is not None:
            isc.authority = self.authority

        # Get the supported sign_id list
        sign_id_list = isc._img_config_parser.sign_id_list

        # Generating signed images for sign_ids available in sign_id list
        if sign_id is None:
            for sign in range(len(sign_id_list)):
                isc.set_image_path(dp_file, sign_id_list[sign])
                isc.output_dir = os.path.dirname(dp_file)
                isc.image_info_list[0].dest_image.image_dir_ext = ''

                # Process the debug policy
                isc.process(sign=True)

                # Check if the signing is done or not
                if not isc.image_info_list[
                        0].status.sign.state == isc.image_info_list[
                            0].status.sign.SUCCESS:
                    raise RuntimeError(
                        'Failed to sign the debugpolicy elf file: ' +
                        isc.image_info_list[0].image_under_operation)
                logger.info('Signed debugpolicy elf file at: ' +
                            isc.image_info_list[0].image_under_operation)
                self.input_file_list.append(
                    isc.image_info_list[0].image_under_operation)

                if os.path.isfile(
                        c_path.join(self.output_dir, 'SecImage_log.txt')):
                    shutil.move(
                        c_path.join(self.output_dir, 'SecImage_log.txt'),
                        c_path.join(
                            self.output_dir,
                            (sign_id_list[sign] + '_secimage_log.txt')))

        # Generating signed image for given sign_id
        else:
            if sign_id not in sign_id_list:
                raise RuntimeError('Received sign_id "' + sign_id +
                                   '" as input.' + '\n'
                                   "       Supported sign_id's are: " +
                                   str(sign_id_list))

            isc.set_image_path(dp_file, sign_id)
            isc.output_dir = os.path.dirname(dp_file)
            isc.image_info_list[0].dest_image.image_dir_ext = ''

            # Process the debug policy
            isc.process(sign=True)

            # Check if the signing is done or not
            if not isc.image_info_list[
                    0].status.sign.state == isc.image_info_list[
                        0].status.sign.SUCCESS:
                raise RuntimeError(
                    'Failed to sign the debugpolicy elf file: ' +
                    isc.image_info_list[0].image_under_operation)
            logger.info('Signed debugpolicy elf file at: ' +
                        isc.image_info_list[0].image_under_operation)
            self.input_file_list.append(
                isc.image_info_list[0].image_under_operation)

            if os.path.isfile(c_path.join(self.output_dir,
                                          'SecImage_log.txt')):
                shutil.move(
                    c_path.join(self.output_dir, 'SecImage_log.txt'),
                    c_path.join(self.output_dir,
                                (sign_id + '_secimage_log.txt')))