tape: use specialized encryption key per media-set

This commit is contained in:
Dietmar Maurer 2021-01-20 17:27:01 +01:00
parent bc228e5eaf
commit 2b191385ea
5 changed files with 65 additions and 14 deletions

View File

@ -1053,7 +1053,9 @@ pub fn catalog_media(
MediaCatalog::destroy(status_path, &media_id.label.uuid)?;
return Ok(());
}
let encrypt_fingerprint = set.encryption_key_fingerprint.clone();
let encrypt_fingerprint = set.encryption_key_fingerprint.clone()
.map(|fp| (fp, set.uuid.clone()));
drive.set_encryption(encrypt_fingerprint)?;
set.pool.clone()

View File

@ -17,6 +17,7 @@ use proxmox::{
cli::*,
RpcEnvironment,
},
tools::Uuid,
};
use proxmox_backup::{
@ -26,6 +27,7 @@ use proxmox_backup::{
LINUX_DRIVE_PATH_SCHEMA,
DRIVE_NAME_SCHEMA,
TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
MEDIA_SET_UUID_SCHEMA,
LinuxTapeDrive,
},
tape::{
@ -193,6 +195,10 @@ fn tape_alert_flags(
schema: TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA,
optional: true,
},
uuid: {
schema: MEDIA_SET_UUID_SCHEMA,
optional: true,
},
drive: {
schema: DRIVE_NAME_SCHEMA,
optional: true,
@ -212,13 +218,25 @@ fn tape_alert_flags(
/// Set or clear encryption key
fn set_encryption(
fingerprint: Option<Fingerprint>,
uuid: Option<Uuid>,
param: Value,
) -> Result<(), Error> {
let result = proxmox::try_block!({
let mut handle = get_tape_handle(&param)?;
handle.set_encryption(fingerprint)?;
match (fingerprint, uuid) {
(Some(fingerprint), Some(uuid)) => {
handle.set_encryption(Some((fingerprint, uuid)))?;
}
(Some(_), None) => {
bail!("missing media set uuid");
}
(None, _) => {
handle.set_encryption(None)?;
}
}
Ok(())
}).map_err(|err: Error| err.to_string());

View File

@ -7,6 +7,7 @@ use anyhow::{bail, format_err, Error};
use nix::fcntl::{fcntl, FcntlArg, OFlag};
use proxmox::sys::error::SysResult;
use proxmox::tools::Uuid;
use crate::{
config,
@ -535,16 +536,33 @@ impl TapeDriver for LinuxTapeHandle {
/// Note: Only 'root' user may run RAW SG commands, so we need to
/// spawn setuid binary 'sg-tape-cmd'. Also, encryption key file
/// is only readable by root.
fn set_encryption(&mut self, key_fingerprint: Option<Fingerprint>) -> Result<(), Error> {
fn set_encryption(
&mut self,
key_fingerprint: Option<(Fingerprint, Uuid)>,
) -> Result<(), Error> {
if nix::unistd::Uid::effective().is_root() {
if let Some(ref key_fingerprint) = key_fingerprint {
if let Some((ref key_fingerprint, ref uuid)) = key_fingerprint {
let (key_map, _digest) = config::tape_encryption_keys::load_keys()?;
match key_map.get(key_fingerprint) {
Some(item) => {
return set_encryption(&mut self.file, Some(item.key));
// derive specialized key for each media-set
let mut tape_key = [0u8; 32];
let uuid_bytes: [u8; 16] = uuid.as_bytes().clone();
openssl::pkcs5::pbkdf2_hmac(
&item.key,
&uuid_bytes,
10,
openssl::hash::MessageDigest::sha256(),
&mut tape_key)?;
return set_encryption(&mut self.file, Some(tape_key));
}
None => bail!("unknown tape encryption key '{}'", key_fingerprint),
}
@ -556,9 +574,10 @@ impl TapeDriver for LinuxTapeHandle {
let mut command = std::process::Command::new(
"/usr/lib/x86_64-linux-gnu/proxmox-backup/sg-tape-cmd");
command.args(&["encryption"]);
if let Some(fingerprint) = key_fingerprint {
if let Some((fingerprint, uuid)) = key_fingerprint {
let fingerprint = crate::tools::format::as_fingerprint(fingerprint.bytes());
command.args(&["--fingerprint", &fingerprint]);
command.args(&["--uuid", &uuid.to_string()]);
}
command.args(&["--stdin"]);
command.stdin(unsafe { std::process::Stdio::from_raw_fd(self.file.as_raw_fd())});

View File

@ -22,8 +22,13 @@ use anyhow::{bail, format_err, Error};
use ::serde::{Deserialize};
use serde_json::Value;
use proxmox::tools::io::ReadExt;
use proxmox::api::section_config::SectionConfigData;
use proxmox::{
tools::{
Uuid,
io::ReadExt,
},
api::section_config::SectionConfigData,
};
use crate::{
backup::{
@ -190,7 +195,14 @@ pub trait TapeDriver {
}
/// Set or clear encryption key
fn set_encryption(&mut self, key_fingerprint: Option<Fingerprint>) -> Result<(), Error> {
///
/// We use the media_set_uuid to XOR the secret key with the
/// uuid (first 16 bytes), so that each media set uses an uique
/// key for encryption.
fn set_encryption(
&mut self,
key_fingerprint: Option<(Fingerprint, Uuid)>,
) -> Result<(), Error> {
if key_fingerprint.is_some() {
bail!("drive does not support encryption");
}

View File

@ -231,12 +231,12 @@ impl PoolWriter {
media.id(),
)?;
let encrypt_fingerprint = media
.media_set_label()
.as_ref()
.unwrap()
let media_set = media.media_set_label().clone().unwrap();
let encrypt_fingerprint = media_set
.encryption_key_fingerprint
.clone();
.clone()
.map(|fp| (fp, media_set.uuid.clone()));
drive.set_encryption(encrypt_fingerprint)?;