src/bin/proxmox-backup-client.rs - key API: pass kdf parameter

Allow to store keys without password.
This commit is contained in:
Dietmar Maurer 2019-06-18 18:21:01 +02:00
parent 9b06db4563
commit 181f097af9
2 changed files with 99 additions and 51 deletions

View File

@ -57,13 +57,44 @@ impl KeyDerivationConfig {
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
pub struct KeyConfig { pub struct KeyConfig {
kdf: Option<KeyDerivationConfig>, pub kdf: Option<KeyDerivationConfig>,
#[serde(with = "proxmox::tools::serde::date_time_as_rfc3339")] #[serde(with = "proxmox::tools::serde::date_time_as_rfc3339")]
created: DateTime<Local>, pub created: DateTime<Local>,
#[serde(with = "proxmox::tools::serde::bytes_as_base64")] #[serde(with = "proxmox::tools::serde::bytes_as_base64")]
data: Vec<u8>, pub data: Vec<u8>,
} }
pub fn store_key_config(
path: &std::path::Path,
replace: bool,
key_config: KeyConfig,
) -> Result<(), Error> {
let data = serde_json::to_string(&key_config)?;
use std::io::Write;
try_block!({
if replace {
let mode = nix::sys::stat::Mode::S_IRUSR | nix::sys::stat::Mode::S_IWUSR;
crate::tools::file_set_contents(&path, data.as_bytes(), Some(mode))?;
} else {
use std::os::unix::fs::OpenOptionsExt;
let mut file = std::fs::OpenOptions::new()
.write(true)
.mode(0o0600)
.create_new(true)
.open(&path)?;
file.write_all(data.as_bytes())?;
}
Ok(())
}).map_err(|err: Error| format_err!("Unable to create file {:?} - {}", path, err))?;
Ok(())
}
pub fn store_key_with_passphrase( pub fn store_key_with_passphrase(
path: &std::path::Path, path: &std::path::Path,
@ -104,37 +135,11 @@ pub fn store_key_with_passphrase(
let created = Local.timestamp(Local::now().timestamp(), 0); let created = Local.timestamp(Local::now().timestamp(), 0);
store_key_config(path, replace, KeyConfig {
let key_config = KeyConfig {
kdf: Some(kdf), kdf: Some(kdf),
created, created,
data: enc_data, data: enc_data,
}; })
let data = serde_json::to_string(&key_config)?;
use std::io::Write;
try_block!({
if replace {
let mode = nix::sys::stat::Mode::S_IRUSR | nix::sys::stat::Mode::S_IWUSR;
crate::tools::file_set_contents(&path, data.as_bytes(), Some(mode))?;
} else {
use std::os::unix::fs::OpenOptionsExt;
let mut file = std::fs::OpenOptions::new()
.write(true)
.mode(0o0600)
.create_new(true)
.open(&path)?;
file.write_all(data.as_bytes())?;
}
Ok(())
}).map_err(|err: Error| format_err!("Unable to create file {:?} - {}", path, err))?;
Ok(())
} }
pub fn load_and_decrtypt_key(path: &std::path::Path, passphrase: fn() -> Result<Vec<u8>, Error>) -> Result<Vec<u8>, Error> { pub fn load_and_decrtypt_key(path: &std::path::Path, passphrase: fn() -> Result<Vec<u8>, Error>) -> Result<Vec<u8>, Error> {

View File

@ -812,18 +812,34 @@ fn key_create(
let path = tools::required_string_param(&param, "path")?; let path = tools::required_string_param(&param, "path")?;
let path = PathBuf::from(path); let path = PathBuf::from(path);
// always read from tty let kdf = param["kdf"].as_str().unwrap_or("scrypt");
let key = proxmox::sys::linux::random_data(32)?;
if kdf == "scrypt" {
// always read passphrase from tty
if !crate::tools::tty::stdin_isatty() { if !crate::tools::tty::stdin_isatty() {
bail!("unable to read passphrase - no tty"); bail!("unable to read passphrase - no tty");
} }
let password = crate::tools::tty::read_password("Encryption Key Password: ")?; let password = crate::tools::tty::read_password("Encryption Key Password: ")?;
let key = proxmox::sys::linux::random_data(32)?;
store_key_with_passphrase(&path, &key, &password, false)?; store_key_with_passphrase(&path, &key, &password, false)?;
Ok(Value::Null) Ok(Value::Null)
} else if kdf == "none" {
let created = Local.timestamp(Local::now().timestamp(), 0);
store_key_config(&path, false, KeyConfig {
kdf: None,
created,
data: key,
})?;
Ok(Value::Null)
} else {
unreachable!();
}
} }
@ -836,6 +852,8 @@ fn key_change_passphrase(
let path = tools::required_string_param(&param, "path")?; let path = tools::required_string_param(&param, "path")?;
let path = PathBuf::from(path); let path = PathBuf::from(path);
let kdf = param["kdf"].as_str().unwrap_or("scrypt");
// we need a TTY to query the new password // we need a TTY to query the new password
if !crate::tools::tty::stdin_isatty() { if !crate::tools::tty::stdin_isatty() {
bail!("unable to change passphrase - no tty"); bail!("unable to change passphrase - no tty");
@ -843,6 +861,8 @@ fn key_change_passphrase(
let key = load_and_decrtypt_key(&path, get_encryption_key_password)?; let key = load_and_decrtypt_key(&path, get_encryption_key_password)?;
if kdf == "scrypt" {
let new_pw = String::from_utf8(crate::tools::tty::read_password("New Password: ")?)?; let new_pw = String::from_utf8(crate::tools::tty::read_password("New Password: ")?)?;
let verify_pw = String::from_utf8(crate::tools::tty::read_password("Verify Password: ")?)?; let verify_pw = String::from_utf8(crate::tools::tty::read_password("Verify Password: ")?)?;
@ -857,16 +877,38 @@ fn key_change_passphrase(
store_key_with_passphrase(&path, &key, new_pw.as_bytes(), true)?; store_key_with_passphrase(&path, &key, new_pw.as_bytes(), true)?;
Ok(Value::Null) Ok(Value::Null)
} else if kdf == "none" {
// fixme: keep original creation time, add modified timestamp ??
let created = Local.timestamp(Local::now().timestamp(), 0);
store_key_config(&path, true, KeyConfig {
kdf: None,
created,
data: key,
})?;
Ok(Value::Null)
} else {
unreachable!();
}
} }
fn key_mgmt_cli() -> CliCommandMap { fn key_mgmt_cli() -> CliCommandMap {
let kdf_schema: Arc<Schema> = Arc::new(
StringSchema::new("Key derivation function. Choose 'none' to store the key unecrypted.")
.format(Arc::new(ApiStringFormat::Enum(&["scrypt", "none"])))
.default("scrypt")
.into()
);
// fixme: change-passphrase, import, export, list // fixme: change-passphrase, import, export, list
let key_create_cmd_def = CliCommand::new( let key_create_cmd_def = CliCommand::new(
ApiMethod::new( ApiMethod::new(
key_create, key_create,
ObjectSchema::new("Create a new encryption key.") ObjectSchema::new("Create a new encryption key.")
.required("path", StringSchema::new("File system path.")) .required("path", StringSchema::new("File system path."))
.optional("kdf", kdf_schema.clone())
)) ))
.arg_param(vec!["path"]) .arg_param(vec!["path"])
.completion_cb("path", tools::complete_file_name); .completion_cb("path", tools::complete_file_name);
@ -876,6 +918,7 @@ fn key_mgmt_cli() -> CliCommandMap {
key_change_passphrase, key_change_passphrase,
ObjectSchema::new("Change the passphrase required to decrypt the key.") ObjectSchema::new("Change the passphrase required to decrypt the key.")
.required("path", StringSchema::new("File system path.")) .required("path", StringSchema::new("File system path."))
.optional("kdf", kdf_schema.clone())
)) ))
.arg_param(vec!["path"]) .arg_param(vec!["path"])
.completion_cb("path", tools::complete_file_name); .completion_cb("path", tools::complete_file_name);