Example #1
0
    def _process_secure_operation(self, image, progress, integrity_check, sign, encrypt, 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
        image.encdec = encdec
        parsegen = self._status_updater(self._create_parsegen_obj,
                                        image.status.parsegen,
                                        progress, True,
                                        image)

        # Set the security mechanisms
        parsegen.integrity_check = parsegen.contains_integrity_check() or integrity_check
        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,
                                 progress, True,
                                 image, parsegen)

        # Package and generate the output image file
        if integrity_check or sign or encrypt:
            store_data_to_file(image.dest_image.image_path, parsegen.get_data())
            if integrity_check:
                image.status.integrity_check.state = StatusInfo.SUCCESS
            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,
                                 progress, True,
                                 image, image.config.post_process.pil_splitter,
                                 getattr(self._stager, '_meta_build_path', None))

        # 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))
Example #2
0
    def dump_signer_debug_data(self, image, sign_assets):
        if image.dest_image.debug_dir_signer is None:
            return
        c_path.create_debug_dir(image.dest_image.debug_dir_signer)

        sa = sign_assets
        fp = image.dest_image
        from imageinfo import DestImagePath
        assert isinstance(fp, DestImagePath)

        debug_logs = [
            (sa.root_cert, fp.debug_file_signer_root_cert),
            (sa.attestation_ca_cert, fp.debug_file_signer_attestation_ca_cert),
            (sa.attestation_cert, fp.debug_file_signer_attestation_cert),
            (sa.signature, fp.debug_file_signer_signature),
            (sa.cert_chain, fp.debug_file_signer_cert_chain)
        ]

        # Save the private attributes too
        debug_logs += [
            (sa.root_key, fp.debug_file_signer_root_key),
            (sa.attestation_ca_key, fp.debug_file_signer_attestation_ca_key),
            (sa.attestation_key, fp.debug_file_signer_attestation_key)
        ]

        for data, debug_file in debug_logs:
            try:
                store_data_to_file(debug_file, data)
            except Exception:
                logger.debug2('Failed to save debug file ' + debug_file + '\n'
                              '    ' + str(sys.exc_info()[1]))
    def _create_parsegen_obj(self, image):
        c_path.create_debug_dir(image.dest_image.debug_dir_parsegen)
        from sectools.features.isc.parsegen import get_parser
        parsegen = get_parser(image)

        # Check if parsegen authority settings are correct
        parsegen.authority = self.authority
        parsegen.validate_authority()

        return parsegen
Example #4
0
    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)
        sign_assets = signer.sign(parsegen.data_to_sign, image)

        # 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
Example #5
0
    def dump_signer_debug_data(self, image, sign_assets, parsegen):
        if image.dest_image.debug_dir_signer is None:
            return
        c_path.create_debug_dir(image.dest_image.debug_dir_signer)

        sa = sign_assets
        fp = image.dest_image
        from imageinfo import DestImagePath
        assert isinstance(fp, DestImagePath)

        # Backup parsegen authority
        authority = parsegen.authority

        # QTI Signature and Cert Chain
        parsegen.authority = defines.AUTHORITY_QTI
        data_signature_qti = parsegen.data_signature
        cert_chain_qti = parsegen.cert_chain

        # OEM Signature and Cert Chain
        parsegen.authority = defines.AUTHORITY_OEM
        data_signature = parsegen.data_signature
        cert_chain = parsegen.cert_chain

        # Restore authority
        parsegen.authority = authority

        debug_logs = [
            (sa.root_cert, fp.debug_file_signer_root_cert),
            (sa.attestation_ca_cert, fp.debug_file_signer_attestation_ca_cert),
            (sa.attestation_cert, fp.debug_file_signer_attestation_cert),
            (data_signature, fp.debug_file_signer_signature),
            (cert_chain, fp.debug_file_signer_cert_chain),
            (data_signature_qti, fp.debug_file_signer_qti_signature),
            (cert_chain_qti, fp.debug_file_signer_qti_cert_chain)
        ]

        # Save the private attributes too
        debug_logs += [
            (sa.root_key, fp.debug_file_signer_root_key),
            (sa.attestation_ca_key, fp.debug_file_signer_attestation_ca_key),
            (sa.attestation_key, fp.debug_file_signer_attestation_key)
        ]

        for data, debug_file in debug_logs:
            try:
                store_data_to_file(debug_file, data)
            except Exception:
                logger.debug2('Failed to save debug file ' + debug_file + '\n'
                              '    ' + str(sys.exc_info()[1]))
Example #6
0
    def _create_parsegen_obj(self,
                             image,
                             validating=False,
                             signing=False,
                             prefix_override=None,
                             sign_attr=False):
        c_path.create_debug_dir(image.dest_image.debug_dir_parsegen)
        from sectools.features.isc.parsegen import get_parser
        parsegen = get_parser(image, validating, signing, prefix_override,
                              sign_attr)

        # Check if parsegen authority settings are correct
        parsegen.authority = self.authority
        parsegen.validate_authority()

        return parsegen
    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 _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
Example #9
0
    def dump_signer_debug_data(self, image, sign_assets, parsegen, more_debug_logs=[]):
        if image.dest_image.debug_dir_signer is None:
            return
        c_path.create_debug_dir(image.dest_image.debug_dir_signer)

        sa = sign_assets
        fp = image.dest_image
        assert isinstance(fp, self.dest_image_path_class)

        # Backup parsegen authority
        authority = parsegen.authority

        # OEM Signature and Cert Chain
        parsegen.authority = AUTHORITY_OEM
        data_signature = parsegen.data_signature
        cert_chain = parsegen.cert_chain

        # Restore authority
        parsegen.authority = authority

        debug_logs = [(sa.root_cert, fp.debug_file_signer_root_cert),
                      (sa.attestation_ca_cert, fp.debug_file_signer_attestation_ca_cert),
                      (sa.attestation_cert, fp.debug_file_signer_attestation_cert),
                      (data_signature, fp.debug_file_signer_signature),
                      (cert_chain, fp.debug_file_signer_cert_chain)]

        for dbg_log in more_debug_logs:
            debug_logs.append((dbg_log[0], getattr(fp, dbg_log[1])))

        # Save the private attributes too
        debug_logs += [(sa.root_key, fp.debug_file_signer_root_key),
                       (sa.attestation_ca_key, fp.debug_file_signer_attestation_ca_key),
                       (sa.attestation_key, fp.debug_file_signer_attestation_key)]

        for data, debug_file in debug_logs:
            try:
                store_data_to_file(debug_file, data)
            except Exception:
                logger.debug2('Failed to save debug file ' + debug_file + '\n'
                              '    ' + str(sys.exc_info()[1]))
Example #10
0
    def _create_parsegen_obj(self, image, validating=False, signing=False, file_exists=True,
                             parsegens=None, sign_attr=False):
        c_path.create_debug_dir(image.dest_image.debug_dir_parsegen)

        image_path = image.src_image.image_path
        image_name = os.path.basename(image_path)
        image_base, image_ext = os.path.splitext(image_name)

        data = load_data_from_file(image_path) if file_exists else None
        parsegen = ElfMbnV3Base(data,
                                imageinfo=image,
                                debug_dir=image.dest_image.debug_dir_parsegen,
                                debug_prefix=image_base,
                                debug_suffix=image_ext,
                                validating=validating,
                                signing=signing,
                                parsegens=parsegens,
                                sign_attr=sign_attr)

        # Check if parsegen authority settings are correct
        parsegen.authority = self.authority
        parsegen.validate_authority()

        return parsegen
 def _create_parsegen_obj(self, image):
     c_path.create_debug_dir(image.dest_image.debug_dir_parsegen)
     parsegen = get_parser(image)
     return parsegen
Example #12
0
 def _create_parsegen_obj(self, image):
     c_path.create_debug_dir(image.dest_image.debug_dir_parsegen)
     from sectools.features.isc.parsegen import get_parser
     parsegen = get_parser(image)
     return parsegen
Example #13
0
    def _process_validation(self,
                            image,
                            progress,
                            security_policy_list,
                            i_val_image,
                            i_val_integrity_check,
                            i_val_sign,
                            i_val_encrypt,
                            idx=0):
        # TODO: Need to figure how to do this
        #image.dest_image._mid = 'validation'

        # 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
        val_image = i_val_image
        val_integrity_check = security_policy_list[
            idx].integrity_check and i_val_integrity_check
        val_sign = security_policy_list[idx].sign and i_val_sign
        val_encrypt = security_policy_list[idx].encrypt and i_val_encrypt

        # 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

        # Update the souce image path
        image.src_image.image_dir_base = os.path.dirname(
            image.image_under_operation)
        image.src_image.image_dir_ext = ''
        image.src_image.image_name = os.path.basename(
            image.image_under_operation)

        try:
            # Create the encryptor object
            encdec = None
            if val_encrypt and image.general_properties.selected_encryptor:
                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.validate_parsegen,
                                                progress, True, image)
            finally:
                image.image_type.file_type = file_type_backup
                image.encdec = encdec_backup

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

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

            # Validate parsegen
            if val_image:
                self._status_updater(self._validate_parsegen,
                                     image.status.validate_parsegen, progress,
                                     False, image, parsegen)

            # Validate integrity check
            if val_integrity_check:
                self._status_updater(self._validate_integrity_check,
                                     image.status.validate_integrity_check,
                                     progress, False, image, parsegen)

            # Validate sign
            if val_sign:
                self._status_updater(self._validate_sign,
                                     image.status.validate_sign, progress,
                                     False, image, parsegen)

            # Validate encrypt
            if val_encrypt:
                self._status_updater(self._validate_encrypt,
                                     image.status.validate_encrypt, progress,
                                     False, 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 image_under_operation here
                image_under_operation_int = image.image_under_operation
                image.image_under_operation = tmp_fd.name

                try:
                    self._process_validation(image, progress,
                                             security_policy_list, i_val_image,
                                             i_val_integrity_check, i_val_sign,
                                             i_val_encrypt, idx + 1)
                finally:
                    image.image_under_operation = image_under_operation_int

                os.remove(tmp_fd.name)

        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

        return parsegen
    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
Example #15
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 is_TA(image.signing_attributes.sw_id):
                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
Example #16
0
    def _process_validation(self, image, progress, val_image, val_integrity_check, val_sign, val_encrypt):
        # TODO: Need to figure how to do this
        #image.dest_image._mid = 'validation'

        # 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(image.image_under_operation)
        image.src_image.image_dir_ext = ''
        image.src_image.image_name = os.path.basename(image.image_under_operation)

        try:
            # Create the encryptor object
            encdec = None
            if val_encrypt:
                try:
                    c_path.create_debug_dir(image.dest_image.debug_dir_encdec)
                    encdec = get_encdec(image)
                except Exception:
                    pass

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

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

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

            # Validate parsegen
            if val_image:
                self._status_updater(self._validate_parsegen,
                                     image.status.validate_parsegen,
                                     progress, False,
                                     image, parsegen)

            # Validate integrity check
            if val_integrity_check:
                self._status_updater(self._validate_integrity_check,
                                     image.status.validate_integrity_check,
                                     progress, False,
                                     image, parsegen)

            # Validate sign
            if val_sign:
                self._status_updater(self._validate_sign,
                                     image.status.validate_sign,
                                     progress, False,
                                     image, parsegen)

            # Validate encrypt
            if val_encrypt:
                self._status_updater(self._validate_encrypt,
                                     image.status.validate_encrypt,
                                     progress, False,
                                     image, parsegen)

        except Exception:
            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
            raise
        else:
            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
Example #17
0
    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)

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

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

                # 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()
 def _create_parsegen_obj(self, image):
     c_path.create_debug_dir(image.dest_image.debug_dir_parsegen)
     from sectools.features.isc.parsegen import get_parser
     parsegen = get_parser(image)
     return parsegen
    def _process_validation(self, image, progress, security_policy_list,
                            i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx=0):
        # TODO: Need to figure how to do this
        #image.dest_image._mid = 'validation'

        # 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
        val_image = i_val_image
        val_integrity_check = security_policy_list[idx].integrity_check and i_val_integrity_check
        val_sign = security_policy_list[idx].sign and i_val_sign
        val_encrypt = security_policy_list[idx].encrypt and i_val_encrypt

        # 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

        # Update the souce image path
        image.src_image.image_dir_base = os.path.dirname(image.image_under_operation)
        image.src_image.image_dir_ext = ''
        image.src_image.image_name = os.path.basename(image.image_under_operation)

        try:
            # Create the encryptor object
            encdec = None
            if val_encrypt:
                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.validate_parsegen,
                                                progress, True,
                                                image)
            finally:
                image.image_type.file_type = file_type_backup
                image.encdec = encdec_backup

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

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

            # Validate parsegen
            if val_image:
                self._status_updater(self._validate_parsegen,
                                     image.status.validate_parsegen,
                                     progress, False,
                                     image, parsegen)

            # Validate integrity check
            if val_integrity_check:
                self._status_updater(self._validate_integrity_check,
                                     image.status.validate_integrity_check,
                                     progress, False,
                                     image, parsegen)

            # Validate sign
            if val_sign:
                self._status_updater(self._validate_sign,
                                     image.status.validate_sign,
                                     progress, False,
                                     image, parsegen)

            # Validate encrypt
            if val_encrypt:
                self._status_updater(self._validate_encrypt,
                                     image.status.validate_encrypt,
                                     progress, False,
                                     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 image_under_operation here
                image_under_operation_int = image.image_under_operation
                image.image_under_operation = tmp_fd.name

                try:
                    self._process_validation(image, progress, security_policy_list,
                                             i_val_image, i_val_integrity_check, i_val_sign, i_val_encrypt, idx + 1)
                finally:
                    image.image_under_operation = image_under_operation_int

                os.remove(tmp_fd.name)

        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

        return parsegen
Example #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()
Example #21
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')
Example #22
0
    def _process_secure_operation(self,
                                  image,
                                  progress,
                                  security_policy_list,
                                  i_integrity_check,
                                  i_sign,
                                  i_encrypt,
                                  i_decrypt,
                                  idx=0):
        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 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
Example #23
0
    def _process_validation(self,
                            image,
                            progress,
                            security_policy_list,
                            i_val_image,
                            i_val_integrity_check,
                            i_val_sign,
                            i_val_encrypt,
                            idx=0,
                            prefix_override=None):
        # TODO: Need to figure how to do this
        #image.dest_image._mid = 'validation'

        # 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
        val_image = i_val_image
        val_integrity_check = security_policy_list[
            idx].integrity_check and i_val_integrity_check
        val_sign = security_policy_list[idx].sign and i_val_sign
        val_encrypt = security_policy_list[idx].encrypt and i_val_encrypt

        # 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

        # Update the souce image path
        image.src_image.image_dir_base = os.path.dirname(
            image.image_under_operation)
        image.src_image.image_dir_ext = ''
        image.src_image.image_name = os.path.basename(
            image.image_under_operation)

        try:
            # 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, True)

            # 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.validate_parsegen,
                                                progress, True, image, True,
                                                False, prefix_override)
            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,
                parsegen.is_encrypted())

            # Prevent validation when using an encrypted key provider
            from sectools.features.isc.encryption_service.unified import encrypted_key_provider_id_supported
            encrypted_key_provider_id = image.signing_attributes.UIE_key
            if parsegen.is_encrypted() and encrypted_key_provider_id_supported(
                    encrypted_key_provider_id):
                raise RuntimeError(
                    "The image is encrypted. Validation is not supported when using an encrypted key provider.\n"
                    "Try again with validation disabled.")

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

            # Validate parsegen
            if val_image:
                self._status_updater(self._validate_parsegen,
                                     image.status.validate_parsegen, progress,
                                     False, image, parsegen)

            # Validate integrity check
            if val_integrity_check:
                self._status_updater(self._validate_integrity_check,
                                     image.status.validate_integrity_check,
                                     progress, False, image, parsegen)

            # Validate sign
            if val_sign:
                self._status_updater(self._validate_sign,
                                     image.status.validate_sign, progress,
                                     False, image, parsegen)

            # Validate encrypt
            if val_encrypt:

                self._status_updater(self._validate_encrypt,
                                     image.status.validate_encrypt, progress,
                                     False, image, parsegen)

            # 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(
                    prefix=security_policy_list[idx + 1].file_type,
                    delete=False)
                tmp_fd.close()
                store_data_to_file(tmp_fd.name, data)

                # Backup the image_under_operation here
                image_under_operation_int = image.image_under_operation
                image.image_under_operation = tmp_fd.name

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

                try:
                    self._process_validation(image, progress,
                                             security_policy_list, i_val_image,
                                             i_val_integrity_check, i_val_sign,
                                             i_val_encrypt, idx + 1,
                                             prefix_override)
                finally:
                    image.image_under_operation = image_under_operation_int

                os.remove(tmp_fd.name)

        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

        return parsegen
    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()
Example #25
0
        def _process(idx, image, integrity_check, sign,
                     val_image, val_integrity_check, val_sign):
            assert isinstance(image, ImageInfoIot)

            logger.info('------------------------------------------------------')
            status_string = ('Processing: ' + 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, 'IoT_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:
                    parsegen = self._process_secure_operation(
                        image, progress, security_policy_list, integrity_check, sign,
                        parsegens=parsegens.get(image.chipset, list()))

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

                # 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)):
                    image.status.overall.state = StatusInfo.SUCCESS

            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')
Example #26
0
    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,
                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 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
            from sectools.common.crypto import crypto_functions
            version = 'v' + crypto.discovery.openssl.OPENSSL_VERSION_MIN + ' or greater '
            crypto_functions.are_available([crypto_functions.MOD_OPENSSL])
            path_info = 'is available at: "' + crypto.openssl_binary_implementation.openssl_binary_path + '"'
        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
        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)

                # 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, 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 RemoteSignerNote as e:
                logger.info('NOTE: ' + str(e), color=logger.YELLOW)

            except Exception:
                logger.error(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()