]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/config/tape_encryption_keys.rs
03c39c58dffc60712cd1975a44cdc65861e363be
[proxmox-backup.git] / src / api2 / config / tape_encryption_keys.rs
1 use anyhow::{bail, Error};
2 use serde_json::Value;
3
4 use proxmox_router::{ApiMethod, Router, RpcEnvironment, Permission};
5 use proxmox_schema::api;
6
7 use pbs_api_types::{
8 Fingerprint, KeyInfo, Kdf,
9 TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
10 PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA,
11 PRIV_TAPE_AUDIT, PRIV_TAPE_MODIFY,
12 };
13
14 use pbs_config::key_config::KeyConfig;
15 use pbs_config::open_backup_lockfile;
16 use pbs_config::tape_encryption_keys::{
17 TAPE_KEYS_LOCKFILE,
18 load_keys,
19 load_key_configs,
20 save_keys,
21 save_key_configs,
22 insert_key,
23 };
24
25 #[api(
26 input: {
27 properties: {},
28 },
29 returns: {
30 description: "The list of tape encryption keys (with config digest).",
31 type: Array,
32 items: { type: KeyInfo },
33 },
34 access: {
35 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_AUDIT, false),
36 },
37 )]
38 /// List existing keys
39 pub fn list_keys(
40 _param: Value,
41 _info: &ApiMethod,
42 mut rpcenv: &mut dyn RpcEnvironment,
43 ) -> Result<Vec<KeyInfo>, Error> {
44
45 let (key_map, digest) = load_key_configs()?;
46
47 let mut list = Vec::new();
48
49 for (_fingerprint, item) in key_map.iter() {
50 list.push(item.into());
51 }
52
53 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
54
55 Ok(list)
56 }
57
58 #[api(
59 protected: true,
60 input: {
61 properties: {
62 kdf: {
63 type: Kdf,
64 optional: true,
65 },
66 fingerprint: {
67 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
68 },
69 password: {
70 description: "The current password.",
71 min_length: 5,
72 },
73 "new-password": {
74 description: "The new password.",
75 min_length: 5,
76 },
77 hint: {
78 schema: PASSWORD_HINT_SCHEMA,
79 },
80 digest: {
81 optional: true,
82 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
83 },
84 },
85 },
86 access: {
87 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_MODIFY, false),
88 },
89 )]
90 /// Change the encryption key's password (and password hint).
91 pub fn change_passphrase(
92 kdf: Option<Kdf>,
93 password: String,
94 new_password: String,
95 hint: String,
96 fingerprint: Fingerprint,
97 digest: Option<String>,
98 _rpcenv: &mut dyn RpcEnvironment
99 ) -> Result<(), Error> {
100
101 let kdf = kdf.unwrap_or_default();
102
103 if let Kdf::None = kdf {
104 bail!("Please specify a key derivation function (none is not allowed here).");
105 }
106
107 let _lock = open_backup_lockfile(TAPE_KEYS_LOCKFILE, None, true)?;
108
109 let (mut config_map, expected_digest) = load_key_configs()?;
110
111 if let Some(ref digest) = digest {
112 let digest = proxmox::tools::hex_to_digest(digest)?;
113 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
114 }
115
116 let key_config = match config_map.get(&fingerprint) {
117 Some(key_config) => key_config,
118 None => bail!("tape encryption key '{}' does not exist.", fingerprint),
119 };
120
121 let (key, created, fingerprint) = key_config.decrypt(&|| Ok(password.as_bytes().to_vec()))?;
122 let mut new_key_config = KeyConfig::with_key(&key, new_password.as_bytes(), kdf)?;
123 new_key_config.created = created; // keep original value
124 new_key_config.hint = Some(hint);
125
126 config_map.insert(fingerprint, new_key_config);
127
128 save_key_configs(config_map)?;
129
130 Ok(())
131 }
132
133 #[api(
134 protected: true,
135 input: {
136 properties: {
137 kdf: {
138 type: Kdf,
139 optional: true,
140 },
141 password: {
142 description: "A secret password.",
143 min_length: 5,
144 },
145 hint: {
146 schema: PASSWORD_HINT_SCHEMA,
147 },
148 },
149 },
150 returns: {
151 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
152 },
153 access: {
154 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_MODIFY, false),
155 },
156 )]
157 /// Create a new encryption key
158 pub fn create_key(
159 kdf: Option<Kdf>,
160 password: String,
161 hint: String,
162 _rpcenv: &mut dyn RpcEnvironment
163 ) -> Result<Fingerprint, Error> {
164
165 let kdf = kdf.unwrap_or_default();
166
167 if let Kdf::None = kdf {
168 bail!("Please specify a key derivation function (none is not allowed here).");
169 }
170
171 let (key, mut key_config) = KeyConfig::new(password.as_bytes(), kdf)?;
172 key_config.hint = Some(hint);
173
174 let fingerprint = key_config.fingerprint.clone().unwrap();
175
176 insert_key(key, key_config, false)?;
177
178 Ok(fingerprint)
179 }
180
181
182 #[api(
183 input: {
184 properties: {
185 fingerprint: {
186 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
187 },
188 },
189 },
190 returns: {
191 type: KeyInfo,
192 },
193 access: {
194 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_AUDIT, false),
195 },
196 )]
197 /// Get key config (public key part)
198 pub fn read_key(
199 fingerprint: Fingerprint,
200 _rpcenv: &mut dyn RpcEnvironment,
201 ) -> Result<KeyInfo, Error> {
202
203 let (config_map, _digest) = load_key_configs()?;
204
205 let key_config = match config_map.get(&fingerprint) {
206 Some(key_config) => key_config,
207 None => bail!("tape encryption key '{}' does not exist.", fingerprint),
208 };
209
210 if key_config.kdf.is_none() {
211 bail!("found unencrypted key - internal error");
212 }
213
214 Ok(key_config.into())
215 }
216
217 #[api(
218 protected: true,
219 input: {
220 properties: {
221 fingerprint: {
222 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
223 },
224 digest: {
225 optional: true,
226 schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
227 },
228 },
229 },
230 access: {
231 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_MODIFY, false),
232 },
233 )]
234 /// Remove a encryption key from the database
235 ///
236 /// Please note that you can no longer access tapes using this key.
237 pub fn delete_key(
238 fingerprint: Fingerprint,
239 digest: Option<String>,
240 _rpcenv: &mut dyn RpcEnvironment,
241 ) -> Result<(), Error> {
242 let _lock = open_backup_lockfile(TAPE_KEYS_LOCKFILE, None, true)?;
243
244 let (mut config_map, expected_digest) = load_key_configs()?;
245 let (mut key_map, _) = load_keys()?;
246
247 if let Some(ref digest) = digest {
248 let digest = proxmox::tools::hex_to_digest(digest)?;
249 crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?;
250 }
251
252 match config_map.get(&fingerprint) {
253 Some(_) => { config_map.remove(&fingerprint); },
254 None => bail!("tape encryption key '{}' does not exist.", fingerprint),
255 }
256 save_key_configs(config_map)?;
257
258 key_map.remove(&fingerprint);
259 save_keys(key_map)?;
260
261 Ok(())
262 }
263
264 const ITEM_ROUTER: Router = Router::new()
265 .get(&API_METHOD_READ_KEY)
266 .put(&API_METHOD_CHANGE_PASSPHRASE)
267 .delete(&API_METHOD_DELETE_KEY);
268
269 pub const ROUTER: Router = Router::new()
270 .get(&API_METHOD_LIST_KEYS)
271 .post(&API_METHOD_CREATE_KEY)
272 .match_all("fingerprint", &ITEM_ROUTER);