tape: implement change-passphrase for tape encryption keys
This commit is contained in:
		| @ -30,6 +30,7 @@ use crate::{ | |||||||
|         TapeKeyMetadata, |         TapeKeyMetadata, | ||||||
|     }, |     }, | ||||||
|     backup::{ |     backup::{ | ||||||
|  |         KeyConfig, | ||||||
|         Kdf, |         Kdf, | ||||||
|         Fingerprint, |         Fingerprint, | ||||||
|     }, |     }, | ||||||
| @ -68,6 +69,83 @@ pub fn list_keys( | |||||||
|  |  | ||||||
|     Ok(list) |     Ok(list) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[api( | ||||||
|  |     input: { | ||||||
|  |         properties: { | ||||||
|  |             kdf: { | ||||||
|  |                 type: Kdf, | ||||||
|  |                 optional: true, | ||||||
|  |             }, | ||||||
|  |             fingerprint: { | ||||||
|  |                 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, | ||||||
|  |             }, | ||||||
|  |             password: { | ||||||
|  |                 description: "The current password.", | ||||||
|  |                 min_length: 5, | ||||||
|  |             }, | ||||||
|  |             "new-password": { | ||||||
|  |                 description: "The new password.", | ||||||
|  |                 min_length: 5, | ||||||
|  |             }, | ||||||
|  |             hint: { | ||||||
|  |                 schema: PASSWORD_HINT_SCHEMA, | ||||||
|  |             }, | ||||||
|  |             digest: { | ||||||
|  |                 optional: true, | ||||||
|  |                 schema: PROXMOX_CONFIG_DIGEST_SCHEMA, | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | )] | ||||||
|  | /// Change the encryption key's password (and password hint). | ||||||
|  | pub fn change_passphrase( | ||||||
|  |     kdf: Option<Kdf>, | ||||||
|  |     password: String, | ||||||
|  |     new_password: String, | ||||||
|  |     hint: String, | ||||||
|  |     fingerprint: Fingerprint, | ||||||
|  |     digest: Option<String>, | ||||||
|  |     _rpcenv: &mut dyn RpcEnvironment | ||||||
|  | ) -> Result<(), Error> { | ||||||
|  |  | ||||||
|  |     let kdf = kdf.unwrap_or_default(); | ||||||
|  |  | ||||||
|  |     if let Kdf::None = kdf { | ||||||
|  |         bail!("Please specify a key derivation  funktion (none is not allowed here)."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let _lock = open_file_locked( | ||||||
|  |         TAPE_KEYS_LOCKFILE, | ||||||
|  |         std::time::Duration::new(10, 0), | ||||||
|  |         true, | ||||||
|  |     )?; | ||||||
|  |  | ||||||
|  |     let (mut config_map, expected_digest) = load_key_configs()?; | ||||||
|  |  | ||||||
|  |     if let Some(ref digest) = digest { | ||||||
|  |         let digest = proxmox::tools::hex_to_digest(digest)?; | ||||||
|  |         crate::tools::detect_modified_configuration_file(&digest, &expected_digest)?; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let key_config = match config_map.get(&fingerprint) { | ||||||
|  |         Some(key_config) => key_config, | ||||||
|  |         None => bail!("tape encryption key '{}' does not exist.", fingerprint), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     let (key, created, fingerprint) = key_config.decrypt(&|| Ok(password.as_bytes().to_vec()))?; | ||||||
|  |     let mut new_key_config = KeyConfig::with_key(&key, new_password.as_bytes(), kdf)?; | ||||||
|  |     new_key_config.created = created; // keep original value | ||||||
|  |     new_key_config.fingerprint = Some(fingerprint.clone()); | ||||||
|  |     new_key_config.hint = Some(hint); | ||||||
|  |  | ||||||
|  |     config_map.insert(fingerprint, new_key_config); | ||||||
|  |  | ||||||
|  |     save_key_configs(config_map)?; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
| #[api( | #[api( | ||||||
|     protected: true, |     protected: true, | ||||||
|     input: { |     input: { | ||||||
| @ -165,7 +243,7 @@ pub fn delete_key( | |||||||
|  |  | ||||||
| const ITEM_ROUTER: Router = Router::new() | const ITEM_ROUTER: Router = Router::new() | ||||||
|     //.get(&API_METHOD_READ_KEY_METADATA) |     //.get(&API_METHOD_READ_KEY_METADATA) | ||||||
|     //.put(&API_METHOD_UPDATE_KEY_METADATA) |     .put(&API_METHOD_CHANGE_PASSPHRASE) | ||||||
|     .delete(&API_METHOD_DELETE_KEY); |     .delete(&API_METHOD_DELETE_KEY); | ||||||
|  |  | ||||||
| pub const ROUTER: Router = Router::new() | pub const ROUTER: Router = Router::new() | ||||||
|  | |||||||
| @ -17,6 +17,8 @@ use proxmox_backup::{ | |||||||
|         self, |         self, | ||||||
|         types::{ |         types::{ | ||||||
|             DRIVE_NAME_SCHEMA, |             DRIVE_NAME_SCHEMA, | ||||||
|  |             TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, | ||||||
|  |             PASSWORD_HINT_SCHEMA, | ||||||
|         }, |         }, | ||||||
|     }, |     }, | ||||||
|     backup::Kdf, |     backup::Kdf, | ||||||
| @ -31,6 +33,12 @@ pub fn encryption_key_commands() -> CommandLineInterface { | |||||||
|             "create", |             "create", | ||||||
|             CliCommand::new(&API_METHOD_CREATE_KEY) |             CliCommand::new(&API_METHOD_CREATE_KEY) | ||||||
|         ) |         ) | ||||||
|  |         .insert( | ||||||
|  |             "change-passphrase", | ||||||
|  |             CliCommand::new(&API_METHOD_CHANGE_PASSPHRASE) | ||||||
|  |                 .arg_param(&["fingerprint"]) | ||||||
|  |                 .completion_cb("fingerprint", complete_key_fingerprint) | ||||||
|  |         ) | ||||||
|         .insert( |         .insert( | ||||||
|             "restore", |             "restore", | ||||||
|             CliCommand::new(&API_METHOD_RESTORE_KEY) |             CliCommand::new(&API_METHOD_RESTORE_KEY) | ||||||
| @ -46,6 +54,49 @@ pub fn encryption_key_commands() -> CommandLineInterface { | |||||||
|     cmd_def.into() |     cmd_def.into() | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #[api( | ||||||
|  |     input: { | ||||||
|  |         properties: { | ||||||
|  |             kdf: { | ||||||
|  |                 type: Kdf, | ||||||
|  |                 optional: true, | ||||||
|  |             }, | ||||||
|  |             fingerprint: { | ||||||
|  |                 schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA, | ||||||
|  |             }, | ||||||
|  |             hint: { | ||||||
|  |                 schema: PASSWORD_HINT_SCHEMA, | ||||||
|  |                 optional: true, | ||||||
|  |             }, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | )] | ||||||
|  | /// Change the encryption key's password. | ||||||
|  | fn change_passphrase( | ||||||
|  |     mut param: Value, | ||||||
|  |     rpcenv: &mut dyn RpcEnvironment, | ||||||
|  | ) -> Result<(), Error> { | ||||||
|  |  | ||||||
|  |     if !tty::stdin_isatty() { | ||||||
|  |         bail!("unable to change passphrase - no tty"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let password = tty::read_password("Current Tape Encryption Key Password: ")?; | ||||||
|  |  | ||||||
|  |     let new_password = tty::read_and_verify_password("New Tape Encryption Key Password: ")?; | ||||||
|  |  | ||||||
|  |     param["password"] = String::from_utf8(password)?.into(); | ||||||
|  |     param["new-password"] = String::from_utf8(new_password)?.into(); | ||||||
|  |  | ||||||
|  |     let info = &api2::config::tape_encryption_keys::API_METHOD_CHANGE_PASSPHRASE; | ||||||
|  |     match info.handler { | ||||||
|  |         ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?, | ||||||
|  |         _ => unreachable!(), | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
| #[api( | #[api( | ||||||
|     input: { |     input: { | ||||||
|         properties: { |         properties: { | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user