[pve-devel] [PATCH proxmox-backup-qemu] api: add master key support
Fabian Grünbichler
f.gruenbichler at proxmox.com
Mon Feb 8 14:08:32 CET 2021
this is a breaking change/API extension.
Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---
Notes:
requires appropriate Breaks on old pve-qemu-kvm, and versioned build and
runtime dep from pve-qemu-kvm on bumped libproxmox-backup-qemu.
backwards compat with outdated QEMU + lib versions is handled in qemu-server
current-api.h | 1 +
src/backup.rs | 45 ++++++++++++++++++++++++++++++++++++---------
src/commands.rs | 10 ++++++++++
src/lib.rs | 9 +++++++++
4 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/current-api.h b/current-api.h
index abe7e89..ddf65d5 100644
--- a/current-api.h
+++ b/current-api.h
@@ -176,6 +176,7 @@ ProxmoxBackupHandle *proxmox_backup_new(const char *repo,
const char *password,
const char *keyfile,
const char *key_password,
+ const char *master_keyfile,
bool compress,
bool encrypt,
const char *fingerprint,
diff --git a/src/backup.rs b/src/backup.rs
index e2062e7..8f64979 100644
--- a/src/backup.rs
+++ b/src/backup.rs
@@ -8,9 +8,11 @@ use futures::future::{Future, Either, FutureExt};
use tokio::runtime::Runtime;
use proxmox_backup::tools::runtime::get_runtime_with_builder;
-use proxmox_backup::backup::{CryptConfig, CryptMode, BackupDir, BackupManifest, load_and_decrypt_key};
+use proxmox_backup::backup::{CryptConfig, CryptMode, BackupDir, BackupManifest, KeyConfig, load_and_decrypt_key, rsa_encrypt_key_config};
use proxmox_backup::client::{HttpClient, HttpClientOptions, BackupWriter};
+use proxmox::tools::fs::file_get_contents;
+
use super::BackupSetup;
use crate::capi_types::*;
use crate::registry::Registry;
@@ -22,6 +24,7 @@ pub(crate) struct BackupTask {
compress: bool,
crypt_mode: CryptMode,
crypt_config: Option<Arc<CryptConfig>>,
+ rsa_encrypted_key: Option<Vec<u8>>,
writer: OnceCell<Arc<BackupWriter>>,
last_manifest: OnceCell<Arc<BackupManifest>>,
manifest: Arc<Mutex<BackupManifest>>,
@@ -44,16 +47,28 @@ impl BackupTask {
runtime: Arc<Runtime>
) -> Result<Self, Error> {
- let crypt_config = match setup.keyfile {
- None => None,
+ let (crypt_config, rsa_encrypted_key) = match setup.keyfile {
+ None => (None, None),
Some(ref path) => {
- let (key, _, _) = load_and_decrypt_key(path, & || {
+ let (key, created, _) = load_and_decrypt_key(path, & || {
match setup.key_password {
Some(ref key_password) => Ok(key_password.as_bytes().to_vec()),
None => bail!("no key_password specified"),
}
})?;
- Some(Arc::new(CryptConfig::new(key)?))
+ let rsa_encrypted_key = match setup.master_keyfile {
+ Some(ref master_keyfile) => {
+ let pem = file_get_contents(master_keyfile)?;
+ let rsa = openssl::rsa::Rsa::public_key_from_pem(&pem)?;
+
+ let mut key_config = KeyConfig::without_password(key)?;
+ key_config.created = created; // keep original value
+
+ Some(rsa_encrypt_key_config(rsa, &key_config)?)
+ },
+ None => None,
+ };
+ (Some(Arc::new(CryptConfig::new(key)?)), rsa_encrypted_key)
}
};
@@ -65,10 +80,21 @@ impl BackupTask {
let registry = Arc::new(Mutex::new(Registry::<ImageUploadInfo>::new()));
let known_chunks = Arc::new(Mutex::new(HashSet::new()));
- Ok(Self { runtime, setup, compress, crypt_mode, crypt_config, abort,
- registry, manifest, known_chunks,
- writer: OnceCell::new(), last_manifest: OnceCell::new(),
- aborted: OnceCell::new() })
+ Ok(Self {
+ runtime,
+ setup,
+ compress,
+ crypt_mode,
+ crypt_config,
+ rsa_encrypted_key,
+ abort,
+ registry,
+ manifest,
+ known_chunks,
+ writer: OnceCell::new(),
+ last_manifest: OnceCell::new(),
+ aborted: OnceCell::new()
+ })
}
pub fn new(setup: BackupSetup, compress: bool, crypt_mode: CryptMode) -> Result<Self, Error> {
@@ -258,6 +284,7 @@ impl BackupTask {
let command_future = finish_backup(
self.need_writer()?,
self.crypt_config.clone(),
+ self.rsa_encrypted_key.clone(),
Arc::clone(&self.manifest),
);
diff --git a/src/commands.rs b/src/commands.rs
index c63c4f7..5fdf318 100644
--- a/src/commands.rs
+++ b/src/commands.rs
@@ -438,8 +438,18 @@ pub(crate) async fn write_data(
pub(crate) async fn finish_backup(
client: Arc<BackupWriter>,
crypt_config: Option<Arc<CryptConfig>>,
+ rsa_encrypted_key: Option<Vec<u8>>,
manifest: Arc<Mutex<BackupManifest>>,
) -> Result<c_int, Error> {
+ if let Some(rsa_encrypted_key) = rsa_encrypted_key {
+ let target = ENCRYPTED_KEY_BLOB_NAME;
+ let options = UploadOptions { compress: false, encrypt: false, ..UploadOptions::default() };
+ let stats = client
+ .upload_blob_from_data(rsa_encrypted_key, target, options)
+ .await?;
+ manifest.lock().unwrap().add_file(target.to_string(), stats.size, stats.csum, CryptMode::Encrypt)?;
+ };
+
let manifest = {
let guard = manifest.lock().unwrap();
diff --git a/src/lib.rs b/src/lib.rs
index fd7c064..05d7b58 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -137,6 +137,7 @@ pub(crate) struct BackupSetup {
pub password: String,
pub keyfile: Option<std::path::PathBuf>,
pub key_password: Option<String>,
+ pub master_keyfile: Option<std::path::PathBuf>,
pub fingerprint: Option<String>,
}
@@ -208,6 +209,7 @@ pub extern "C" fn proxmox_backup_new(
password: *const c_char,
keyfile: *const c_char,
key_password: *const c_char,
+ master_keyfile: *const c_char,
compress: bool,
encrypt: bool,
fingerprint: *const c_char,
@@ -227,6 +229,11 @@ pub extern "C" fn proxmox_backup_new(
let keyfile = tools::utf8_c_string(keyfile)?.map(std::path::PathBuf::from);
let key_password = tools::utf8_c_string(key_password)?;
let fingerprint = tools::utf8_c_string(fingerprint)?;
+ let master_keyfile = tools::utf8_c_string(master_keyfile)?.map(std::path::PathBuf::from);
+
+ if master_keyfile.is_some() && keyfile.is_none() {
+ return Err(format_err!("can't use master keyfile without keyfile"));
+ }
let crypt_mode = if keyfile.is_some() {
if encrypt { CryptMode::Encrypt } else { CryptMode::SignOnly }
@@ -246,6 +253,7 @@ pub extern "C" fn proxmox_backup_new(
backup_time: backup_time as i64,
keyfile,
key_password,
+ master_keyfile,
fingerprint,
};
@@ -720,6 +728,7 @@ pub extern "C" fn proxmox_restore_new(
backup_time,
keyfile,
key_password,
+ master_keyfile: None,
fingerprint,
};
--
2.20.1
More information about the pve-devel
mailing list