| // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef ZXCRYPT_FDIO_VOLUME_H_ | 
 | #define ZXCRYPT_FDIO_VOLUME_H_ | 
 |  | 
 | #include <lib/fdio/fdio.h> | 
 | #include <lib/fdio/cpp/caller.h> | 
 | #include <lib/zx/channel.h> | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include <fbl/function.h> | 
 | #include <fbl/string.h> | 
 | #include <fbl/unique_fd.h> | 
 | #include <fbl/vector.h> | 
 |  | 
 | #include "src/security/fcrypto/secret.h" | 
 | #include "src/security/zxcrypt/volume.h" | 
 |  | 
 | namespace zxcrypt { | 
 |  | 
 | // Describes what activity we are performing: creating a new volume from | 
 | // scratch, or unsealing an existing volume.  Different activities may prefer | 
 | // different key sources for migration reasons. | 
 | enum Activity { | 
 |   Create, | 
 |   Unseal, | 
 | }; | 
 |  | 
 | enum KeySourcePolicy { | 
 |   // Always uses a key of all zeroes. | 
 |   NullSource, | 
 |  | 
 |   // Always uses a key from the TEE; fail if not available | 
 |   TeeRequiredSource, | 
 |  | 
 |   // Always uses a key from the TEE for new volumes; | 
 |   // allows fallback to null key for unsealing volumes | 
 |   TeeTransitionalSource, | 
 |  | 
 |   // Attempts to use a key from the TEE for new volumes and unlocking, but | 
 |   // falls back to null key if TEE key fails | 
 |   TeeOpportunisticSource, | 
 |  | 
 |   // someday: TpmSource variants? | 
 | }; | 
 |  | 
 | enum KeySource { | 
 |   kNullSource, | 
 |   kTeeSource, | 
 | }; | 
 |  | 
 | // Computes the ordered list of key sources that should be used in the context | 
 | // under the policy |ksp|. | 
 | fbl::Vector<KeySource> ComputeEffectiveCreatePolicy(KeySourcePolicy ksp); | 
 | fbl::Vector<KeySource> ComputeEffectiveUnsealPolicy(KeySourcePolicy ksp); | 
 |  | 
 | // Calls |callback| on a key provided by each key source in | 
 | // |ordered_key_sources| until either the callback returns ZX_OK or the callback | 
 | // has returned some error on all key sources in |ordered_key_sources|. | 
 | zx_status_t TryWithKeysFrom( | 
 |     const fbl::Vector<KeySource>& ordered_key_sources, Activity activity, | 
 |     fbl::Function<zx_status_t(std::unique_ptr<uint8_t[]>, size_t)> callback); | 
 |  | 
 | // |zxcrypt::FdioVolumeManager| represents a channel to an instance of a bound | 
 | // zxcrypt device (named "zxcrypt" in the device tree). | 
 | class __EXPORT FdioVolumeManager { | 
 |  public: | 
 |   explicit FdioVolumeManager(zx::channel&& chan); | 
 |  | 
 |   // Request that the volume provided by the manager represented by |chan| be | 
 |   // unsealed with the given key material/slot.  If successful, the driver | 
 |   // will create a child device named |unsealed| which exposes a block interface. | 
 |   zx_status_t Unseal(const uint8_t* key, size_t key_len, uint8_t slot); | 
 |  | 
 |   // Request that the volume provided by the manager represented by |chan| be | 
 |   // unsealed with an product-defined device key associated with the specified | 
 |   // slot.  The caller must have access to /boot/config/zxcrypt in its | 
 |   // namespace to use this function.  If successful, the driver will create a | 
 |   // child device named |unsealed| which exposes a block interface. | 
 |   zx_status_t UnsealWithDeviceKey(uint8_t slot); | 
 |  | 
 |   // Request that the volume provided by the manager represented by |chan| be | 
 |   // sealed.  After calling this method, it is an error to make any further | 
 |   // calls with this FdioVolumeManager. | 
 |   zx_status_t Seal(); | 
 |  | 
 |   // Request that the volume provided by the manager represented by |chan| be | 
 |   // shredded, permanently rendering the device unable to be |Unseal|ed again in | 
 |   // the future.  This renders all data on the volume permanently inaccessible | 
 |   // once it is sealed. | 
 |   zx_status_t Shred(); | 
 |  | 
 |  private: | 
 |   // The underlying zxcrypt device, accessed over FDIO | 
 |   zx::channel chan_; | 
 | }; | 
 |  | 
 | // |zxcrypt::FdioVolume| is a zxcrypt volume which does IO via a file | 
 | // descriptor.  It can be used on the host to prepare zxcrypt images, and | 
 | // is often more convenient for testing. | 
 | class __EXPORT FdioVolume final : public Volume { | 
 |  public: | 
 |   explicit FdioVolume(fbl::unique_fd&& block_dev_fd, fbl::unique_fd&& devfs_root_fd); | 
 |  | 
 |   // Creates a new zxcrypt volume associated with the given file descriptor, | 
 |   // |block_dev_fd|, which must live in the device tree rooted at | 
 |   // |devfs_root_fd|, and returns it via |out|, if provided.  This will format | 
 |   // the block device as zxcrypt using the given |key|, which will be | 
 |   // associated with key slot 0.  This method takes ownership of | 
 |   // |block_dev_fd| and |devfs_root_fd|.  Note that |key| is not strengthened | 
 |   // and MUST have cryptographic key length of at least 128 bits. | 
 |   static zx_status_t Create(fbl::unique_fd block_dev_fd, fbl::unique_fd devfs_root_fd, | 
 |                             const crypto::Secret& key, std::unique_ptr<FdioVolume>* out = nullptr); | 
 |  | 
 |   // Does the same as |Create| but with the key provided by a product-defined | 
 |   // source.  The caller must have access to /boot/config/zxcrypt in its | 
 |   // namespace to use this function. | 
 |   static zx_status_t CreateWithDeviceKey(fbl::unique_fd&& block_dev_fd, | 
 |                                          fbl::unique_fd&& devfs_root_fd, | 
 |                                          std::unique_ptr<FdioVolume>* out); | 
 |  | 
 |   // Opens a zxcrypt volume on the block device described by |block_dev_fd| | 
 |   // (from the device tree rooted at |devfs_root_fd|) using the |key| | 
 |   // corresponding to given key |slot|.  The |block_dev_fd| parameter means | 
 |   // this method can be used from libzxcrypt. This method takes ownership of | 
 |   // |block_dev_fd| and |devfs_root_fd|.  Note that |key| is not strengthened | 
 |   // and MUST have cryptographic key length of at least 128 bits. | 
 |   static zx_status_t Unlock(fbl::unique_fd block_dev_fd, fbl::unique_fd devfs_root_fd, | 
 |                             const crypto::Secret& key, key_slot_t slot, | 
 |                             std::unique_ptr<FdioVolume>* out); | 
 |  | 
 |   // Opens a zxcrypt volume on the block device described by |block_dev_fd| | 
 |   // (from the device tree rooted at |devfs_root_fd|) using a key from a | 
 |   // product-defined source with the specified |slot|.  The caller must have | 
 |   // access to /boot/config/zxcrypt in their namespace to use this function. | 
 |   // This method takes ownership of |block_dev_fd| and |devfs_root_fd|. | 
 |   static zx_status_t UnlockWithDeviceKey(fbl::unique_fd block_dev_fd, fbl::unique_fd devfs_root_fd, | 
 |                                          key_slot_t slot, std::unique_ptr<FdioVolume>* out); | 
 |  | 
 |   // Returns a new volume object corresponding to the block device given by | 
 |   // |block_dev_fd| (which must live in the device tree hosted by | 
 |   // |devfs_root_fd|) and populated with the block and FVM information. | 
 |   static zx_status_t Init(fbl::unique_fd block_dev_fd, fbl::unique_fd devfs_root_fd, | 
 |                           std::unique_ptr<FdioVolume>* out = nullptr); | 
 |  | 
 |   // Opens a zxcrypt volume on the block device described by |fd| using the |key| corresponding to | 
 |   // given key |slot|. | 
 |   zx_status_t Unlock(const crypto::Secret& key, key_slot_t slot); | 
 |  | 
 |   // Attempts to open the zxcrypt driver device associated with the underlying | 
 |   // block device described by |fd|, binding the driver if necessary, | 
 |   // and returning a channel to the zxcrypt device node. | 
 |   zx_status_t OpenManager(const zx::duration& timeout, zx_handle_t* out); | 
 |  | 
 |   // Opens the block device exposed atop this volume and returns a file | 
 |   // descriptor to it via |out|, or fails if the volume isn't available within | 
 |   // |timeout|. | 
 |   zx_status_t Open(const zx::duration& timeout, fbl::unique_fd* out); | 
 |  | 
 |   // Adds a given |key| to the given key |slot|.  This key can then be used to |Open| the | 
 |   // zxcrypt device.  This method can only be called if the volume belongs to libzxcrypt. | 
 |   zx_status_t Enroll(const crypto::Secret& key, key_slot_t slot); | 
 |  | 
 |   // Removes the root key in the given key |slot|.  This key can no longer be used to |Open| the | 
 |   // zxcrypt device.  This method can only be called if the volume belongs to libzxcrypt. | 
 |   zx_status_t Revoke(key_slot_t slot); | 
 |  | 
 |  private: | 
 |   friend class testing::TestDevice; | 
 |  | 
 |   // Retrieves the block and FVM information and adjusts it | 
 |   zx_status_t Init(); | 
 |  | 
 |   zx_status_t GetBlockInfo(BlockInfo* out); | 
 |   zx_status_t GetFvmSliceSize(uint64_t* out); | 
 |   zx_status_t DoBlockFvmVsliceQuery(uint64_t vslice_start, SliceRegion ranges[MAX_SLICE_REGIONS], | 
 |                                     uint64_t* slice_count); | 
 |   zx_status_t DoBlockFvmExtend(uint64_t start_slice, uint64_t slice_count); | 
 |  | 
 |   // Reads a block from the current offset on the underlying device. | 
 |   zx_status_t Read(); | 
 |  | 
 |   // Writes a block to the current offset on the underlying device. | 
 |   zx_status_t Write(); | 
 |  | 
 |   // OpenManager, but using a pre-created fdio_t. | 
 |   zx_status_t OpenManagerWithCaller(fdio_cpp::UnownedFdioCaller& caller, const zx::duration& timeout, | 
 |                                     zx_handle_t* out); | 
 |  | 
 |   // Returns the topological path of the underlying block device, relative to | 
 |   // |devfs_root_fd| | 
 |   zx_status_t RelativeTopologicalPath(fdio_cpp::UnownedFdioCaller& caller, fbl::String* out); | 
 |  | 
 |   // The underlying block device, accessed over FDIO | 
 |   fbl::unique_fd block_dev_fd_; | 
 |  | 
 |   // The root of the device tree, needed to openat() related devices via | 
 |   // constructing relative topological paths. | 
 |   fbl::unique_fd devfs_root_fd_; | 
 | }; | 
 |  | 
 | }  // namespace zxcrypt | 
 |  | 
 | #endif  // ZXCRYPT_FDIO_VOLUME_H_ |