[pbs-devel] [proxmox-backup v4] fix #3854 paperkey import to proxmox-tape

Markus Frank m.frank at proxmox.com
Wed Mar 9 10:56:10 CET 2022


added a parameter to the cli for reading a old paperkeyfile to restore
the key from it. For that i added a json parameter for the api and made
hint optional because hint is already in the proxmox-backupkey-json.

functionality:
proxmox-tape key paperkey [fingerprint of existing key] > paperkey.backup
proxmox-tape key create --paperkey-file paperkey.backup

for importing the key it is irrelevant, if the paperkey got exported as html
or txt.

Signed-off-by: Markus Frank <m.frank at proxmox.com>
---
version 4:
 * ParameterError::from to param_bail!
 * when hint and paperkey-file used at the same time, old hint get overwritten
 * added text in pbs-tools with function extract_text_between

version 3:
 * ParameterError with method ParameterError::from
 * changed --paperkey_file to --paperkey-file

version 2:
 * added format_err! and ParameterError
 * changed a few "ifs" to "match"

 pbs-tools/src/lib.rs                    |  1 +
 pbs-tools/src/text.rs                   | 20 ++++++++++
 src/api2/config/tape_encryption_keys.rs | 50 ++++++++++++++++++++-----
 src/bin/proxmox_tape/encryption_key.rs  | 31 ++++++++++++++-
 4 files changed, 90 insertions(+), 12 deletions(-)
 create mode 100644 pbs-tools/src/text.rs

diff --git a/pbs-tools/src/lib.rs b/pbs-tools/src/lib.rs
index 939ba7e6..0fb35482 100644
--- a/pbs-tools/src/lib.rs
+++ b/pbs-tools/src/lib.rs
@@ -6,6 +6,7 @@ pub mod lru_cache;
 pub mod nom;
 pub mod sha;
 pub mod ticket;
+pub mod text;
 
 pub mod async_lru_cache;
 
diff --git a/pbs-tools/src/text.rs b/pbs-tools/src/text.rs
new file mode 100644
index 00000000..b8371d06
--- /dev/null
+++ b/pbs-tools/src/text.rs
@@ -0,0 +1,20 @@
+use anyhow::{Error, bail};
+
+pub fn extract_text_between<'a>(text: &'a str, begin: &str, end: &str) -> Result<&'a str, Error> {
+    let begin_i = text.find(begin);
+    let end_i = text.find(end);
+    match (begin_i, end_i) {
+        (Some(begin_i), Some(end_i)) => {
+            if begin_i < end_i {
+                let extracted_text = &text[begin_i + begin.len()..end_i];
+                return Ok(extracted_text);
+            } else {
+                let extracted_text = &text[end_i + end.len()..begin_i];
+                return Ok(extracted_text);
+            }
+        }
+        (_, _) => {
+            bail!("Begin/End-Marker is missing");
+        }
+    }
+}
diff --git a/src/api2/config/tape_encryption_keys.rs b/src/api2/config/tape_encryption_keys.rs
index 3e9a60d1..d8910788 100644
--- a/src/api2/config/tape_encryption_keys.rs
+++ b/src/api2/config/tape_encryption_keys.rs
@@ -174,6 +174,14 @@ pub fn change_passphrase(
             },
             hint: {
                 schema: PASSWORD_HINT_SCHEMA,
+                optional: true,
+            },
+            backupkey: {
+                description: "A previously exported paperkey in JSON format.",
+                type: String,
+                min_length: 300,
+                max_length: 600,
+                optional: true,
             },
         },
     },
@@ -188,7 +196,8 @@ pub fn change_passphrase(
 pub fn create_key(
     kdf: Option<Kdf>,
     password: String,
-    hint: String,
+    hint: Option<String>,
+    backupkey: Option<String>,
     _rpcenv: &mut dyn RpcEnvironment
 ) -> Result<Fingerprint, Error> {
 
@@ -197,15 +206,36 @@ pub fn create_key(
     if let Kdf::None = kdf {
         param_bail!("kdf", format_err!("Please specify a key derivation function (none is not allowed here)."));
     }
-
-    let (key, mut key_config) = KeyConfig::new(password.as_bytes(), kdf)?;
-    key_config.hint = Some(hint);
-
-    let fingerprint = key_config.fingerprint.clone().unwrap();
-
-    insert_key(key, key_config, false)?;
-
-    Ok(fingerprint)
+ 
+    match (hint, backupkey) {
+        (Some(hint), Some(backupkey)) => {
+            let mut key_config: KeyConfig =
+                serde_json::from_str(&backupkey).map_err(|err| format_err!("<errmsg>: {}", err))?;
+            let password_fn = || Ok(password.as_bytes().to_vec());
+            let (key, _created, fingerprint) = key_config.decrypt(&password_fn)?;
+            key_config.hint = Some(hint);
+            insert_key(key, key_config, false)?;
+            Ok(fingerprint)
+        }
+        (None, Some(backupkey)) => {
+            let key_config: KeyConfig =
+                serde_json::from_str(&backupkey).map_err(|err| format_err!("<errmsg>: {}", err))?;
+            let password_fn = || Ok(password.as_bytes().to_vec());
+            let (key, _created, fingerprint) = key_config.decrypt(&password_fn)?;
+            insert_key(key, key_config, false)?;
+            Ok(fingerprint)
+        }
+        (Some(hint), None) => {
+            let (key, mut key_config) = KeyConfig::new(password.as_bytes(), kdf)?;
+            key_config.hint = Some(hint);
+            let fingerprint = key_config.fingerprint.clone().unwrap();
+            insert_key(key, key_config, false)?;
+            Ok(fingerprint)
+        }
+        (_, _) => {
+            param_bail!("hint", format_err!("Please specify either a hint or a backupkey"));
+        }
+    }
 }
 
 
diff --git a/src/bin/proxmox_tape/encryption_key.rs b/src/bin/proxmox_tape/encryption_key.rs
index 71df9ffa..ffda0537 100644
--- a/src/bin/proxmox_tape/encryption_key.rs
+++ b/src/bin/proxmox_tape/encryption_key.rs
@@ -1,8 +1,8 @@
-use anyhow::{bail, Error};
+use anyhow::{format_err, bail, Error};
 use serde_json::Value;
 
 use proxmox_router::{cli::*, ApiHandler, RpcEnvironment};
-use proxmox_schema::api;
+use proxmox_schema::{api, param_bail};
 use proxmox_sys::linux::tty;
 
 use pbs_api_types::{
@@ -12,6 +12,7 @@ use pbs_api_types::{
 
 use pbs_datastore::paperkey::{PaperkeyFormat, generate_paper_key};
 use pbs_config::tape_encryption_keys::{load_key_configs,complete_key_fingerprint};
+use pbs_tools::text::extract_text_between;
 
 use proxmox_backup::api2;
 
@@ -233,6 +234,12 @@ async fn restore_key(
                 type: String,
                 min_length: 1,
                 max_length: 32,
+                optional: true,
+            },
+            "paperkey-file": {
+                description: "Paperkeyfile location for importing old backupkey",
+                type: String,
+                optional: true,
             },
         },
     },
@@ -240,6 +247,7 @@ async fn restore_key(
 /// Create key (read password from stdin)
 fn create_key(
     mut param: Value,
+    paperkey_file: Option<String>,
     rpcenv: &mut dyn RpcEnvironment,
 ) -> Result<(), Error> {
 
@@ -247,6 +255,25 @@ fn create_key(
         bail!("no password input mechanism available");
     }
 
+    if param["hint"].is_null() && paperkey_file.is_none() {
+        param_bail!(
+            "hint",
+            format_err!("Please specify either a hint or a paperkey-file")
+        );
+    }
+
+    // searching for PROXMOX BACKUP KEY if a paperkeyfile is defined
+    if let Some(paperkey_file) = paperkey_file {
+        let data = proxmox_sys::fs::file_read_string(paperkey_file)?;
+        let backupkey = extract_text_between(
+            &data,
+            "-----BEGIN PROXMOX BACKUP KEY-----",
+            "-----END PROXMOX BACKUP KEY-----",
+        )?;
+        param["backupkey"] = backupkey.into();
+        println!("backupkey to import: {}", backupkey);
+    }
+
     let password = tty::read_and_verify_password("Tape Encryption Key Password: ")?;
 
     param["password"] = String::from_utf8(password)?.into();
-- 
2.30.2





More information about the pbs-devel mailing list