]> git.proxmox.com Git - proxmox-backup.git/blame - src/api2/config/tape_encryption_keys.rs
move tape_encryption_keys.rs to pbs_config workspace
[proxmox-backup.git] / src / api2 / config / tape_encryption_keys.rs
CommitLineData
d5a48b5c
DM
1use anyhow::{bail, Error};
2use serde_json::Value;
3
4use proxmox::{
5 api::{
6 api,
7 ApiMethod,
8 Router,
9 RpcEnvironment,
ccdf327a 10 Permission,
d5a48b5c 11 },
d5a48b5c
DM
12};
13
5839c469
DM
14use pbs_api_types::{
15 Fingerprint, KeyInfo, Kdf,
16 TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
17 PROXMOX_CONFIG_DIGEST_SCHEMA, PASSWORD_HINT_SCHEMA,
18};
19
bbdda58b 20use pbs_config::key_config::KeyConfig;
21211748 21use pbs_config::open_backup_lockfile;
5839c469
DM
22use pbs_config::tape_encryption_keys::{
23 TAPE_KEYS_LOCKFILE,
24 load_keys,
25 load_key_configs,
26 save_keys,
27 save_key_configs,
28 insert_key,
29};
86fb3877 30
d5a48b5c
DM
31use crate::{
32 config::{
ccdf327a
DM
33 acl::{
34 PRIV_TAPE_AUDIT,
35 PRIV_TAPE_MODIFY,
36 },
d5a48b5c 37 },
d5a48b5c
DM
38};
39
40#[api(
d5a48b5c
DM
41 input: {
42 properties: {},
43 },
44 returns: {
45 description: "The list of tape encryption keys (with config digest).",
46 type: Array,
69b8bc3b 47 items: { type: KeyInfo },
d5a48b5c 48 },
ccdf327a
DM
49 access: {
50 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_AUDIT, false),
51 },
d5a48b5c
DM
52)]
53/// List existing keys
54pub fn list_keys(
55 _param: Value,
56 _info: &ApiMethod,
57 mut rpcenv: &mut dyn RpcEnvironment,
69b8bc3b 58) -> Result<Vec<KeyInfo>, Error> {
d5a48b5c 59
feb1645f 60 let (key_map, digest) = load_key_configs()?;
d5a48b5c
DM
61
62 let mut list = Vec::new();
feb1645f 63
69b8bc3b
DM
64 for (_fingerprint, item) in key_map.iter() {
65 list.push(item.into());
d5a48b5c 66 }
feb1645f 67
d5a48b5c
DM
68 rpcenv["digest"] = proxmox::tools::digest_to_hex(&digest).into();
69
70 Ok(list)
71}
301b8aa0
DM
72
73#[api(
4dafc513 74 protected: true,
301b8aa0
DM
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 },
ccdf327a
DM
101 access: {
102 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_MODIFY, false),
103 },
301b8aa0
DM
104)]
105/// Change the encryption key's password (and password hint).
106pub 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 {
d1d74c43 119 bail!("Please specify a key derivation function (none is not allowed here).");
301b8aa0
DM
120 }
121
7526d864 122 let _lock = open_backup_lockfile(TAPE_KEYS_LOCKFILE, None, true)?;
301b8aa0
DM
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
301b8aa0
DM
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
d5a48b5c
DM
148#[api(
149 protected: true,
150 input: {
151 properties: {
e5b6c933
DM
152 kdf: {
153 type: Kdf,
154 optional: true,
155 },
d5a48b5c
DM
156 password: {
157 description: "A secret password.",
158 min_length: 5,
159 },
160 hint: {
82a103c8 161 schema: PASSWORD_HINT_SCHEMA,
d5a48b5c
DM
162 },
163 },
164 },
feb1645f
DM
165 returns: {
166 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
167 },
ccdf327a
DM
168 access: {
169 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_MODIFY, false),
170 },
d5a48b5c
DM
171)]
172/// Create a new encryption key
173pub fn create_key(
e5b6c933 174 kdf: Option<Kdf>,
d5a48b5c
DM
175 password: String,
176 hint: String,
177 _rpcenv: &mut dyn RpcEnvironment
178) -> Result<Fingerprint, Error> {
179
e5b6c933
DM
180 let kdf = kdf.unwrap_or_default();
181
182 if let Kdf::None = kdf {
d1d74c43 183 bail!("Please specify a key derivation function (none is not allowed here).");
e5b6c933
DM
184 }
185
1c86893d 186 let (key, mut key_config) = KeyConfig::new(password.as_bytes(), kdf)?;
82a103c8 187 key_config.hint = Some(hint);
d5a48b5c 188
feb1645f 189 let fingerprint = key_config.fingerprint.clone().unwrap();
d5a48b5c 190
18bd6ba1 191 insert_key(key, key_config, false)?;
d5a48b5c
DM
192
193 Ok(fingerprint)
194}
195
196
69b8bc3b
DM
197#[api(
198 input: {
199 properties: {
200 fingerprint: {
201 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
202 },
203 },
204 },
205 returns: {
206 type: KeyInfo,
207 },
ccdf327a
DM
208 access: {
209 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_AUDIT, false),
210 },
69b8bc3b
DM
211)]
212/// Get key config (public key part)
213pub 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
d5a48b5c
DM
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 },
ccdf327a
DM
245 access: {
246 permission: &Permission::Privilege(&["tape", "pool"], PRIV_TAPE_MODIFY, false),
247 },
d5a48b5c
DM
248)]
249/// Remove a encryption key from the database
250///
251/// Please note that you can no longer access tapes using this key.
252pub fn delete_key(
253 fingerprint: Fingerprint,
254 digest: Option<String>,
255 _rpcenv: &mut dyn RpcEnvironment,
256) -> Result<(), Error> {
7526d864 257 let _lock = open_backup_lockfile(TAPE_KEYS_LOCKFILE, None, true)?;
d5a48b5c 258
feb1645f
DM
259 let (mut config_map, expected_digest) = load_key_configs()?;
260 let (mut key_map, _) = load_keys()?;
d5a48b5c
DM
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
feb1645f
DM
267 match config_map.get(&fingerprint) {
268 Some(_) => { config_map.remove(&fingerprint); },
d5a48b5c
DM
269 None => bail!("tape encryption key '{}' does not exist.", fingerprint),
270 }
feb1645f 271 save_key_configs(config_map)?;
d5a48b5c 272
feb1645f 273 key_map.remove(&fingerprint);
d5a48b5c
DM
274 save_keys(key_map)?;
275
276 Ok(())
277}
278
279const ITEM_ROUTER: Router = Router::new()
69b8bc3b 280 .get(&API_METHOD_READ_KEY)
301b8aa0 281 .put(&API_METHOD_CHANGE_PASSPHRASE)
d5a48b5c
DM
282 .delete(&API_METHOD_DELETE_KEY);
283
284pub const ROUTER: Router = Router::new()
285 .get(&API_METHOD_LIST_KEYS)
286 .post(&API_METHOD_CREATE_KEY)
287 .match_all("fingerprint", &ITEM_ROUTER);