Exemple #1
0
    def testAPFSUnlockVolumeOnAPFS(self):
        """Tests the APFSUnlockVolume function on an APFS image."""
        resolver_context = context.Context()

        test_path = self._GetTestFilePath(['apfs.dmg'])
        test_os_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_OS, location=test_path)
        test_raw_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec)
        test_tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_TSK_PARTITION,
            location='/p1',
            parent=test_raw_path_spec)
        test_apfs_container_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_APFS_CONTAINER,
            location='/apfs1',
            parent=test_tsk_partition_path_spec)

        container_file_entry = resolver.Resolver.OpenFileEntry(
            test_apfs_container_path_spec, resolver_context=resolver_context)
        fsapfs_volume = container_file_entry.GetAPFSVolume()

        is_unlocked = apfs_helper.APFSUnlockVolume(
            fsapfs_volume, test_apfs_container_path_spec,
            resolver.Resolver.key_chain)
        self.assertTrue(is_unlocked)
Exemple #2
0
    def Unlock(self, scan_context, path_spec, credential_identifier,
               credential_data):
        """Unlocks a locked scan node e.g. the scan node of an encrypted volume.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      path_spec (PathSpec): path specification of the locked scan node.
      credential_identifier (str): credential identifier used to unlock
          the scan node.
      credential_data (bytes): credential data used to unlock the scan node.

    Returns:
      bool: True if the scan node was successfully unlocked.

    Raises:
      BackEndError: if the scan node cannot be unlocked.
      KeyError: if the scan node does not exists or is not locked.
    """
        if not scan_context.HasScanNode(path_spec):
            raise KeyError('Scan node does not exist.')

        if not scan_context.IsLockedScanNode(path_spec):
            raise KeyError('Scan node is not locked.')

        resolver.Resolver.key_chain.SetCredential(path_spec,
                                                  credential_identifier,
                                                  credential_data)

        if path_spec.type_indicator == definitions.TYPE_INDICATOR_APFS_CONTAINER:
            # TODO: consider changes this when upstream changes have been made.
            # Currently pyfsapfs does not support reading from a volume as a device.
            # Also see: https://github.com/log2timeline/dfvfs/issues/332
            container_file_entry = resolver.Resolver.OpenFileEntry(
                path_spec, resolver_context=self._resolver_context)
            fsapfs_volume = container_file_entry.GetAPFSVolume()

            try:
                is_locked = not apfs_helper.APFSUnlockVolume(
                    fsapfs_volume, path_spec, resolver.Resolver.key_chain)
            except IOError as exception:
                raise errors.BackEndError(
                    'Unable to unlock APFS volume with error: {0!s}'.format(
                        exception))

        else:
            file_object = resolver.Resolver.OpenFileObject(
                path_spec, resolver_context=self._resolver_context)
            is_locked = not file_object or file_object.is_locked
            file_object.close()

        if not is_locked:
            scan_context.UnlockScanNode(path_spec)

        return not is_locked
Exemple #3
0
    def testAPFSUnlockVolumeOnEncryptedAPFS(self):
        """Tests the APFSUnlockVolume function on an encrypted APFS image."""
        resolver.Resolver.key_chain.Empty()

        resolver_context = context.Context()

        test_path = self._GetTestFilePath(['apfs_encrypted.dmg'])
        self._SkipIfPathNotExists(test_path)

        test_os_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_OS, location=test_path)
        test_raw_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_RAW, parent=test_os_path_spec)
        test_tsk_partition_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_TSK_PARTITION,
            location='/p1',
            parent=test_raw_path_spec)
        test_apfs_container_path_spec = path_spec_factory.Factory.NewPathSpec(
            definitions.TYPE_INDICATOR_APFS_CONTAINER,
            location='/apfs1',
            parent=test_tsk_partition_path_spec)

        container_file_entry = resolver.Resolver.OpenFileEntry(
            test_apfs_container_path_spec, resolver_context=resolver_context)
        fsapfs_volume = container_file_entry.GetAPFSVolume()

        is_unlocked = apfs_helper.APFSUnlockVolume(
            fsapfs_volume, test_apfs_container_path_spec,
            resolver.Resolver.key_chain)
        self.assertFalse(is_unlocked)

        resolver.Resolver.key_chain.SetCredential(
            test_apfs_container_path_spec, 'password', self._APFS_PASSWORD)

        is_unlocked = apfs_helper.APFSUnlockVolume(
            fsapfs_volume, test_apfs_container_path_spec,
            resolver.Resolver.key_chain)
        self.assertTrue(is_unlocked)
Exemple #4
0
    def _ScanEncryptedVolumeNode(self, scan_context, scan_node):
        """Scans an encrypted volume node for supported formats.

    Args:
      scan_context (SourceScannerContext): source scanner context.
      scan_node (SourceScanNode): source scan node.

    Raises:
      BackEndError: if the scan node cannot be unlocked.
      ValueError: if the scan context or scan node is invalid.
    """
        if scan_node.type_indicator == definitions.TYPE_INDICATOR_APFS_CONTAINER:
            # TODO: consider changes this when upstream changes have been made.
            # Currently pyfsapfs does not support reading from a volume as a device.
            # Also see: https://github.com/log2timeline/dfvfs/issues/332
            container_file_entry = resolver.Resolver.OpenFileEntry(
                scan_node.path_spec, resolver_context=self._resolver_context)
            fsapfs_volume = container_file_entry.GetAPFSVolume()

            # TODO: unlocking the volume multiple times is inefficient cache volume
            # object in scan node and use is_locked = fsapfs_volume.is_locked()
            try:
                is_locked = not apfs_helper.APFSUnlockVolume(
                    fsapfs_volume, scan_node.path_spec,
                    resolver.Resolver.key_chain)
            except IOError as exception:
                raise errors.BackEndError(
                    'Unable to unlock APFS volume with error: {0!s}'.format(
                        exception))

        else:
            file_object = resolver.Resolver.OpenFileObject(
                scan_node.path_spec, resolver_context=self._resolver_context)
            is_locked = not file_object or file_object.is_locked
            file_object.close()

        if is_locked:
            scan_context.LockScanNode(scan_node.path_spec)

            # For BitLocker To Go add a scan node for the unencrypted part of
            # the volume.
            if scan_node.type_indicator == definitions.TYPE_INDICATOR_BDE:
                path_spec = self.ScanForFileSystem(scan_node.path_spec.parent)
                if path_spec:
                    scan_context.AddScanNode(path_spec, scan_node.parent_node)
Exemple #5
0
    def _Open(self, mode='rb'):
        """Opens the file system defined by path specification.

    Args:
      mode (Optional[str]): file access mode.

    Raises:
      AccessError: if the access to open the file was denied.
      IOError: if the APFS volume could not be retrieved or unlocked.
      OSError: if the APFS volume could not be retrieved or unlocked.
      PathSpecError: if the path specification is incorrect.
      ValueError: if the path specification is invalid.
    """
        if not self._path_spec.HasParent():
            raise errors.PathSpecError(
                'Unsupported path specification without parent.')

        if self._path_spec.parent.type_indicator != (
                definitions.TYPE_INDICATOR_APFS_CONTAINER):
            raise errors.PathSpecError(
                'Unsupported path specification not type APFS container.')

        apfs_container_file_system = resolver.Resolver.OpenFileSystem(
            self._path_spec.parent, resolver_context=self._resolver_context)

        fsapfs_volume = apfs_container_file_system.GetAPFSVolumeByPathSpec(
            self._path_spec.parent)
        if not fsapfs_volume:
            raise IOError('Unable to retrieve APFS volume')

        try:
            is_locked = not apfs_helper.APFSUnlockVolume(
                fsapfs_volume, self._path_spec.parent,
                resolver.Resolver.key_chain)
        except IOError as exception:
            raise IOError(
                'Unable to unlock APFS volume with error: {0!s}'.format(
                    exception))

        if is_locked:
            raise IOError('Unable to unlock APFS volume.')

        self._fsapfs_volume = fsapfs_volume