blob: 1e3d2b6b515e8079b85206476290bc290a7b4662 [file] [log] [blame]
// 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_