lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

policy.rs (6279B)


      1 use crate::error::{RadrootsHostVaultRequirement, RadrootsSecretVaultError};
      2 
      3 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
      4 pub enum RadrootsHostVaultResidency {
      5     UserProfile,
      6     DeviceLocalOnly,
      7 }
      8 
      9 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
     10 pub enum RadrootsHostVaultUserPresencePolicy {
     11     NotRequired,
     12     Required,
     13 }
     14 
     15 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
     16 pub enum RadrootsHostVaultHardwarePolicy {
     17     Any,
     18     PreferHardwareBacked,
     19     RequireHardwareBacked,
     20 }
     21 
     22 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
     23 pub struct RadrootsHostVaultPolicy {
     24     pub residency: RadrootsHostVaultResidency,
     25     pub user_presence: RadrootsHostVaultUserPresencePolicy,
     26     pub hardware: RadrootsHostVaultHardwarePolicy,
     27 }
     28 
     29 impl RadrootsHostVaultPolicy {
     30     #[must_use]
     31     pub const fn desktop() -> Self {
     32         Self {
     33             residency: RadrootsHostVaultResidency::UserProfile,
     34             user_presence: RadrootsHostVaultUserPresencePolicy::NotRequired,
     35             hardware: RadrootsHostVaultHardwarePolicy::Any,
     36         }
     37     }
     38 
     39     #[must_use]
     40     pub const fn device_local() -> Self {
     41         Self {
     42             residency: RadrootsHostVaultResidency::DeviceLocalOnly,
     43             user_presence: RadrootsHostVaultUserPresencePolicy::NotRequired,
     44             hardware: RadrootsHostVaultHardwarePolicy::Any,
     45         }
     46     }
     47 }
     48 
     49 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
     50 pub struct RadrootsHostVaultCapabilities {
     51     pub available: bool,
     52     pub supports_device_local_only: bool,
     53     pub supports_user_presence: bool,
     54     pub supports_hardware_backed: bool,
     55 }
     56 
     57 impl RadrootsHostVaultCapabilities {
     58     #[must_use]
     59     pub const fn unavailable() -> Self {
     60         Self {
     61             available: false,
     62             supports_device_local_only: false,
     63             supports_user_presence: false,
     64             supports_hardware_backed: false,
     65         }
     66     }
     67 
     68     #[must_use]
     69     pub const fn desktop_keyring() -> Self {
     70         Self {
     71             available: true,
     72             supports_device_local_only: false,
     73             supports_user_presence: false,
     74             supports_hardware_backed: false,
     75         }
     76     }
     77 
     78     #[must_use]
     79     pub const fn secure_device() -> Self {
     80         Self {
     81             available: true,
     82             supports_device_local_only: true,
     83             supports_user_presence: true,
     84             supports_hardware_backed: true,
     85         }
     86     }
     87 
     88     pub const fn validate(
     89         self,
     90         policy: RadrootsHostVaultPolicy,
     91     ) -> Result<(), RadrootsSecretVaultError> {
     92         if !self.available {
     93             return Err(RadrootsSecretVaultError::BackendUnavailable {
     94                 backend: crate::backend::RadrootsSecretBackendKind::HostVault,
     95             });
     96         }
     97 
     98         if matches!(
     99             policy.residency,
    100             RadrootsHostVaultResidency::DeviceLocalOnly
    101         ) && !self.supports_device_local_only
    102         {
    103             return Err(RadrootsSecretVaultError::HostVaultPolicyUnsupported {
    104                 requirement: RadrootsHostVaultRequirement::DeviceLocalOnly,
    105             });
    106         }
    107 
    108         if matches!(
    109             policy.user_presence,
    110             RadrootsHostVaultUserPresencePolicy::Required
    111         ) && !self.supports_user_presence
    112         {
    113             return Err(RadrootsSecretVaultError::HostVaultPolicyUnsupported {
    114                 requirement: RadrootsHostVaultRequirement::UserPresence,
    115             });
    116         }
    117 
    118         if matches!(
    119             policy.hardware,
    120             RadrootsHostVaultHardwarePolicy::RequireHardwareBacked
    121         ) && !self.supports_hardware_backed
    122         {
    123             return Err(RadrootsSecretVaultError::HostVaultPolicyUnsupported {
    124                 requirement: RadrootsHostVaultRequirement::HardwareBacked,
    125             });
    126         }
    127 
    128         Ok(())
    129     }
    130 }
    131 
    132 #[cfg(test)]
    133 mod tests {
    134     use super::*;
    135 
    136     #[test]
    137     fn device_local_policy_and_secure_device_capabilities_are_explicit() {
    138         assert_eq!(
    139             RadrootsHostVaultPolicy::device_local(),
    140             RadrootsHostVaultPolicy {
    141                 residency: RadrootsHostVaultResidency::DeviceLocalOnly,
    142                 user_presence: RadrootsHostVaultUserPresencePolicy::NotRequired,
    143                 hardware: RadrootsHostVaultHardwarePolicy::Any,
    144             }
    145         );
    146         assert_eq!(
    147             RadrootsHostVaultCapabilities::secure_device(),
    148             RadrootsHostVaultCapabilities {
    149                 available: true,
    150                 supports_device_local_only: true,
    151                 supports_user_presence: true,
    152                 supports_hardware_backed: true,
    153             }
    154         );
    155         assert_eq!(
    156             RadrootsHostVaultCapabilities::secure_device()
    157                 .validate(RadrootsHostVaultPolicy::device_local()),
    158             Ok(())
    159         );
    160     }
    161 
    162     #[test]
    163     fn validate_reports_user_presence_and_hardware_requirements() {
    164         let user_presence_policy = RadrootsHostVaultPolicy {
    165             residency: RadrootsHostVaultResidency::UserProfile,
    166             user_presence: RadrootsHostVaultUserPresencePolicy::Required,
    167             hardware: RadrootsHostVaultHardwarePolicy::Any,
    168         };
    169         assert_eq!(
    170             RadrootsHostVaultCapabilities::desktop_keyring().validate(user_presence_policy),
    171             Err(RadrootsSecretVaultError::HostVaultPolicyUnsupported {
    172                 requirement: RadrootsHostVaultRequirement::UserPresence,
    173             })
    174         );
    175         assert_eq!(
    176             RadrootsHostVaultCapabilities::secure_device().validate(user_presence_policy),
    177             Ok(())
    178         );
    179 
    180         let hardware_policy = RadrootsHostVaultPolicy {
    181             residency: RadrootsHostVaultResidency::UserProfile,
    182             user_presence: RadrootsHostVaultUserPresencePolicy::NotRequired,
    183             hardware: RadrootsHostVaultHardwarePolicy::RequireHardwareBacked,
    184         };
    185         assert_eq!(
    186             RadrootsHostVaultCapabilities::desktop_keyring().validate(hardware_policy),
    187             Err(RadrootsSecretVaultError::HostVaultPolicyUnsupported {
    188                 requirement: RadrootsHostVaultRequirement::HardwareBacked,
    189             })
    190         );
    191         assert_eq!(
    192             RadrootsHostVaultCapabilities::secure_device().validate(hardware_policy),
    193             Ok(())
    194         );
    195     }
    196 }