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