Skip to main content

fraiseql_core/security/kms/
models.rs

1//! KMS domain models for key management.
2//!
3//! Provides immutable value objects for representing encrypted data,
4//! key references, and rotation policies.
5
6use std::{collections::HashMap, fmt};
7
8use serde::{Deserialize, Serialize};
9use zeroize::Zeroizing;
10
11/// Intended use of the key.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14#[non_exhaustive]
15pub enum KeyPurpose {
16    /// Key used for encryption/decryption
17    EncryptDecrypt,
18    /// Key used for signing/verification
19    SignVerify,
20    /// Key used for message authentication codes
21    Mac,
22}
23
24impl fmt::Display for KeyPurpose {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            Self::EncryptDecrypt => write!(f, "encrypt_decrypt"),
28            Self::SignVerify => write!(f, "sign_verify"),
29            Self::Mac => write!(f, "mac"),
30        }
31    }
32}
33
34/// Current state of the key.
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37#[non_exhaustive]
38pub enum KeyState {
39    /// Key is active and can be used
40    Enabled,
41    /// Key is disabled and cannot be used
42    Disabled,
43    /// Key is pending deletion
44    PendingDeletion,
45    /// Key has been destroyed
46    Destroyed,
47}
48
49impl fmt::Display for KeyState {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        match self {
52            Self::Enabled => write!(f, "enabled"),
53            Self::Disabled => write!(f, "disabled"),
54            Self::PendingDeletion => write!(f, "pending_deletion"),
55            Self::Destroyed => write!(f, "destroyed"),
56        }
57    }
58}
59
60/// Immutable reference to a key in KMS.
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct KeyReference {
63    /// Provider identifier (e.g., 'vault', 'aws', 'gcp')
64    pub provider:   String,
65    /// Provider-specific key identifier
66    pub key_id:     String,
67    /// Human-readable alias (optional)
68    pub key_alias:  Option<String>,
69    /// Intended use of the key
70    pub purpose:    KeyPurpose,
71    /// When the key was created (Unix timestamp)
72    pub created_at: i64,
73}
74
75impl KeyReference {
76    /// Create a new key reference.
77    #[must_use]
78    pub const fn new(
79        provider: String,
80        key_id: String,
81        purpose: KeyPurpose,
82        created_at: i64,
83    ) -> Self {
84        Self {
85            provider,
86            key_id,
87            key_alias: None,
88            purpose,
89            created_at,
90        }
91    }
92
93    /// Set the key alias.
94    #[must_use]
95    pub fn with_alias(mut self, alias: String) -> Self {
96        self.key_alias = Some(alias);
97        self
98    }
99
100    /// Get the fully qualified key identifier.
101    #[must_use]
102    pub fn qualified_id(&self) -> String {
103        format!("{}:{}", self.provider, self.key_id)
104    }
105}
106
107/// Encrypted data with metadata.
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct EncryptedData {
110    /// The encrypted bytes (as hex string for JSON compatibility)
111    pub ciphertext:    String,
112    /// Reference to the key used
113    pub key_reference: KeyReference,
114    /// Encryption algorithm used
115    pub algorithm:     String,
116    /// When encryption occurred (Unix timestamp)
117    pub encrypted_at:  i64,
118    /// Additional authenticated data (AAD)
119    pub context:       HashMap<String, String>,
120}
121
122impl EncryptedData {
123    /// Create new encrypted data.
124    #[must_use]
125    pub const fn new(
126        ciphertext: String,
127        key_reference: KeyReference,
128        algorithm: String,
129        encrypted_at: i64,
130        context: HashMap<String, String>,
131    ) -> Self {
132        Self {
133            ciphertext,
134            key_reference,
135            algorithm,
136            encrypted_at,
137            context,
138        }
139    }
140}
141
142/// Data key pair for envelope encryption.
143#[derive(Debug, Clone)]
144pub struct DataKeyPair {
145    /// Use immediately, never persist
146    pub plaintext_key: Zeroizing<Vec<u8>>,
147    /// Persist alongside encrypted data
148    pub encrypted_key: EncryptedData,
149    /// Master key used for wrapping
150    pub key_reference: KeyReference,
151}
152
153impl DataKeyPair {
154    /// Create a new data key pair.
155    #[must_use]
156    pub fn new(
157        plaintext_key: Vec<u8>,
158        encrypted_key: EncryptedData,
159        key_reference: KeyReference,
160    ) -> Self {
161        Self {
162            plaintext_key: Zeroizing::new(plaintext_key),
163            encrypted_key,
164            key_reference,
165        }
166    }
167}
168
169/// Key rotation configuration.
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct RotationPolicy {
172    /// Whether automatic rotation is enabled
173    pub enabled:              bool,
174    /// Days between rotations
175    pub rotation_period_days: u32,
176    /// When key was last rotated (Unix timestamp, None if never)
177    pub last_rotation:        Option<i64>,
178    /// When key will next be rotated (Unix timestamp, None if not scheduled)
179    pub next_rotation:        Option<i64>,
180}
181
182impl RotationPolicy {
183    /// Create a new rotation policy.
184    #[must_use]
185    pub const fn new(enabled: bool, rotation_period_days: u32) -> Self {
186        Self {
187            enabled,
188            rotation_period_days,
189            last_rotation: None,
190            next_rotation: None,
191        }
192    }
193}