| // Copyright 2021 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 SRC_SECURITY_LIB_ZXCRYPT_CLIENT_H_ |
| #define SRC_SECURITY_LIB_ZXCRYPT_CLIENT_H_ |
| |
| #include <fidl/fuchsia.device/cpp/wire.h> |
| #include <fidl/fuchsia.hardware.block.encrypted/cpp/wire.h> |
| #include <lib/fit/function.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/result.h> |
| |
| #include <memory> |
| |
| #include <fbl/string.h> |
| #include <fbl/unique_fd.h> |
| #include <fbl/vector.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, |
| }; |
| |
| // Reads /pkg/config/zxcrypt to determine what key source policy was selected for this product at |
| // build time. |
| // |
| // Returns the appropriate KeySourcePolicy value if the file contents exactly match a known |
| // configuration value. |
| // Returns ZX_ERR_NOT_FOUND if the config file was not present |
| // Returns ZX_ERR_IO if the config file could not be read |
| // Returns ZX_ERR_BAD_STATE if the config value was not recognized. |
| zx::result<KeySourcePolicy> SelectKeySourcePolicy(); |
| |
| fbl::Vector<KeySource> ComputeEffectiveCreatePolicy(KeySourcePolicy ksp); |
| fbl::Vector<KeySource> ComputeEffectiveUnsealPolicy(KeySourcePolicy ksp); |
| // Computes the ordered list of key sources that should be used in the context |
| // of |activity| under the key source policy |ksp|. |
| fbl::Vector<KeySource> ComputeEffectivePolicy(KeySourcePolicy ksp, Activity activity); |
| |
| // Calls |callback| on a key provided by each key source appropriate for |
| // |activity| until either the callback returns ZX_OK or the callback has |
| // returned some error on all candidate key sources. The caller must have |
| // access to /boot/config/zxcrypt in its namespace to use this function. |
| zx_status_t TryWithImplicitKeys( |
| Activity activity, fit::function<zx_status_t(std::unique_ptr<uint8_t[]>, size_t)> callback); |
| |
| // |zxcrypt::EncryptedVolumeClient| represents a channel to an instance of a bound |
| // zxcrypt device (named "zxcrypt" in the device tree). |
| class __EXPORT EncryptedVolumeClient { |
| public: |
| explicit EncryptedVolumeClient(zx::channel&& channel); |
| |
| // Request that the volume provided by the manager represented by |chan| be |
| // formatted with the given key material/slot, destroying all previous data |
| // and key slots. This function will only succeed on a sealed volume. |
| zx_status_t Format(const uint8_t* key, size_t key_len, uint8_t slot); |
| |
| // Request that the volume provided by the manager represented by |chan| be |
| // formatted with a product-defined device key associated with the specified |
| // slot, destroying any previous superblock. The caller must have access to |
| // /boot/config/zxcrypt in its namespace to use this function. This function |
| // will only succeed on a sealed volume. |
| zx_status_t FormatWithImplicitKey(uint8_t slot); |
| |
| // 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 UnsealWithImplicitKey(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 EncryptedVolumeClient. |
| 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. |
| fidl::ClientEnd<fuchsia_hardware_block_encrypted::DeviceManager> client_end_; |
| }; |
| |
| // |zxcrypt::VolumeManager| manages access to a zxcrypt volume device. In |
| // particular, it ensures that the driver is bound before returning a handle to |
| // the EncryptedVolumeClient. |
| // |
| // Due to the limitations of actions that involve multiple device drivers, |
| // VolumeManager requires access to both the block device we wish to run zxcrypt |
| // atop and the root of the device tree that contains said block device, so that |
| // we can discover child driver nodes in that tree via topological paths, which |
| // are currently the only way to obtain a handle to a newly-bound child. |
| class __EXPORT VolumeManager { |
| public: |
| explicit VolumeManager(fidl::ClientEnd<fuchsia_device::Controller> block_controller, |
| fbl::unique_fd devfs_root_fd); |
| |
| // Unbinds the zxcrypt driver. Invalidates channels previously returned from `OpenClient` and FDs |
| // returned from `OpenInnerBlockDevice`. |
| zx_status_t Unbind(); |
| |
| // Attempts to open the zxcrypt driver device associated with the underlying |
| // block device, binding the driver if necessary, and returning a channel to the zxcrypt device |
| // node. |
| zx_status_t OpenClient(const zx::duration& timeout, zx::channel& out); |
| |
| // Attempts to open the block device representing the inner, unsealed block |
| // device, at a device path of |/zxcrypt/unsealed/block| below the block device. This will only |
| // work once you have called |OpenClient| and used that handle to call |
| // |EncryptedVolumeClient::Unseal| or |EncryptedVolumeClient::UnsealWithImplicitKey|. |
| // This returns the controller to the block device. |
| zx::result<fidl::ClientEnd<fuchsia_device::Controller>> OpenInnerBlockDevice( |
| const zx::duration& timeout); |
| |
| private: |
| // The underlying block device. |
| fidl::ClientEnd<fuchsia_device::Controller> block_controller_; |
| |
| // 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 // SRC_SECURITY_LIB_ZXCRYPT_CLIENT_H_ |