core_auth/backend.rs
1//! Core trait and types for pluggable authentication backends.
2
3use crate::AuthError;
4use core_crypto::SecureBytes;
5use core_types::{AuthFactorId, TrustProfileName};
6use std::collections::BTreeMap;
7use std::path::Path;
8
9/// What kind of user interaction a backend requires.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum AuthInteraction {
12 /// No interaction -- backend can unlock silently (SSH software key, TPM, keyring).
13 None,
14 /// Password/PIN entry required (keyboard input).
15 PasswordEntry,
16 /// Physical touch on hardware token required (FIDO2, PIV with touch policy).
17 HardwareTouch,
18}
19
20/// How the master key should be sent to daemon-secrets.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum IpcUnlockStrategy {
23 /// Use existing `UnlockRequest` with password field.
24 /// daemon-secrets performs the KDF.
25 PasswordUnlock,
26 /// Use `SshUnlockRequest` with pre-derived master key.
27 /// Used by SSH-agent and future backends that derive/unwrap the key client-side.
28 DirectMasterKey,
29}
30
31/// Which piece of the unlock this backend is providing.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum FactorContribution {
34 /// This backend provides a complete master key (unwrapped independently).
35 /// Used in `Any` and `Policy` modes.
36 CompleteMasterKey,
37 /// This backend provides a factor piece for combined derivation.
38 /// Used in `All` mode where the master key is HKDF'd from all pieces.
39 FactorPiece,
40}
41
42/// Result of a successful backend unlock.
43pub struct UnlockOutcome {
44 /// The 32-byte master key (for `DirectMasterKey`) or password bytes (for `PasswordUnlock`).
45 pub master_key: SecureBytes,
46 /// Backend-specific metadata for audit logging.
47 pub audit_metadata: BTreeMap<String, String>,
48 /// Which IPC message type to use.
49 pub ipc_strategy: IpcUnlockStrategy,
50 /// Which factor this outcome represents.
51 pub factor_id: AuthFactorId,
52}
53
54/// A pluggable authentication backend for vault unlock.
55#[async_trait::async_trait]
56pub trait VaultAuthBackend: Send + Sync {
57 /// Which auth factor this backend provides.
58 fn factor_id(&self) -> AuthFactorId;
59
60 /// Human-readable name for audit logs and overlay display.
61 fn name(&self) -> &str;
62
63 /// Short identifier for IPC messages and config.
64 fn backend_id(&self) -> &str;
65
66 /// Check whether this backend has a valid enrollment for the profile.
67 fn is_enrolled(&self, profile: &TrustProfileName, config_dir: &Path) -> bool;
68
69 /// Check whether this backend can currently perform an unlock.
70 /// Must be fast (< 100ms).
71 async fn can_unlock(&self, profile: &TrustProfileName, config_dir: &Path) -> bool;
72
73 /// What kind of user interaction this backend requires.
74 fn requires_interaction(&self) -> AuthInteraction;
75
76 /// Attempt to derive/unwrap the master key for a profile.
77 async fn unlock(
78 &self,
79 profile: &TrustProfileName,
80 config_dir: &Path,
81 salt: &[u8],
82 ) -> Result<UnlockOutcome, AuthError>;
83
84 /// Enroll this backend for a profile. Requires the master key.
85 ///
86 /// `selected_key_index` is an optional index into the list of eligible keys
87 /// returned by the backend. If `None`, the backend picks the first eligible key.
88 async fn enroll(
89 &self,
90 profile: &TrustProfileName,
91 master_key: &SecureBytes,
92 config_dir: &Path,
93 salt: &[u8],
94 selected_key_index: Option<usize>,
95 ) -> Result<(), AuthError>;
96
97 /// Remove enrollment for this backend.
98 async fn revoke(&self, profile: &TrustProfileName, config_dir: &Path) -> Result<(), AuthError>;
99}