Skip to main content

HardwareBoundBackend

Struct HardwareBoundBackend 

Source
pub struct HardwareBoundBackend { /* private fields */ }
Expand description

A KeychainBackend that hardware-binds every blob it stores, degrading to the underlying software envelope when the host has no usable hardware.

§Example

use std::sync::Arc;
use dig_keystore::backend::{BackendKey, FileBackend, KeychainBackend};
use dig_keystore::hardware::{HardwareBoundBackend, HardwarePolicy};

let inner = FileBackend::new("/var/lib/dig/keys");
// No provider available in this build: opens, and says so honestly.
let backend = HardwareBoundBackend::new(inner, None, HardwarePolicy::Optional)?;

// What the HOST can do — the tier a new write would get.
println!("host: {}", backend.tier());

// What protects THIS key — the only answer fit to show a user, because a
// capable host can still hold a keystore that was never wrapped.
let key = BackendKey::new("identity");
let tier = backend.blob_tier(&key)?;
if tier.is_hardware_bound() {
    println!("this key is {tier}");
} else {
    // Never claim protection this key does not have.
    println!("this key is {tier}");
}

Implementations§

Source§

impl HardwareBoundBackend

Source

pub fn new<B: KeychainBackend>( inner: B, provider: Option<Arc<dyn HardwareProvider>>, policy: HardwarePolicy, ) -> Result<Self>

Decorate inner, resolving the protection tier once.

Pass provider = None to store through inner unchanged while reporting DegradeReason::NotRequested.

§Errors

Fails closed rather than silently degrading, per policy:

Source

pub fn with_inner( inner: Arc<dyn KeychainBackend>, provider: Option<Arc<dyn HardwareProvider>>, policy: HardwarePolicy, ) -> Result<Self>

As new, for an already shared backend.

Source

pub fn tier(&self) -> &ProtectionTier

What this host is bound to — the tier every newly written blob gets.

This is a statement about the machine, not about any particular stored key. On a hardware-capable host it reports Hardware even if a given keystore predates hardware binding and is still a bare §3 blob, because a capable host does not retroactively protect bytes already at rest.

Before telling a user that a specific key is hardware-protected, ask blob_tier instead. Rendering “protected by your TPM” from this method would claim copy-resistance that an unwrapped legacy blob does not have.

Source

pub fn blob_tier(&self, key: &BackendKey) -> Result<ProtectionTier>

What protects the key material stored at key, read from the blob itself.

This is the question a UI actually has, and it is not the same as tier: a hardware-capable host can hold a keystore written before hardware binding existed, which is protected by the passphrase envelope alone and does open on another machine. Answering from the stored bytes is what keeps that distinction honest.

The tier reported is the blob’s own, independent of this host: a blob sealed by an Apple Secure Enclave reads as Hardware(MacSecureEnclave) even on Windows. Whether this host can open it is a separate question, answered by read.

§Errors

Both error cases fail closed: a wrapped blob is never reported as software-protected just because this build cannot fully classify it. Guessing in either direction is what this method exists to avoid.

Source

pub fn inner(&self) -> &Arc<dyn KeychainBackend>

The underlying storage, for callers that need it directly.

Trait Implementations§

Source§

impl Debug for HardwareBoundBackend

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Redacted: reports the tier (which is not sensitive and is the point of the type) but never the inner store or any key material.

Source§

impl KeychainBackend for HardwareBoundBackend

Source§

fn read(&self, key: &BackendKey) -> Result<Vec<u8>>

Read a blob, unwrapping it when it carries a hardware envelope.

A blob without the envelope prefix is returned untouched, which is what lets every keystore written before this feature — and any future inner format — keep opening (§5.1).

A blob with an envelope that this host cannot open is an error, never the raw envelope bytes: an envelope copied to a machine without the sealing hardware must fail loudly rather than hand back ciphertext that a caller would then try to parse as a keystore.

Source§

fn write(&self, key: &BackendKey, data: &[u8]) -> Result<()>

Write a blob, sealing it into a hardware envelope in the hardware tier and passing the software-sealed bytes straight through otherwise.

Source§

fn delete(&self, key: &BackendKey) -> Result<()>

Remove the blob at key. Implementations should best-effort overwrite the storage before removing so residual disk sectors do not retain the ciphertext.
Source§

fn list(&self, prefix: &str) -> Result<Vec<BackendKey>>

List keys that start with prefix. Order is unspecified.
Source§

fn exists(&self, key: &BackendKey) -> Result<bool>

Whether a blob exists at key. Default impl delegates to read; backends with cheaper existence checks should override.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.