use std::path::PathBuf;
use base64::{Engine as _, engine::general_purpose};
use clap::Parser;
use cosmian_kms_client::{
ExportObjectParams, KmsClient,
cosmian_kmip::kmip_2_1::kmip_types::CryptographicAlgorithm,
export_object,
kmip_2_1::{kmip_attributes::Attributes, requests::create_symmetric_key_kmip_object},
read_object_from_json_ttlv_file, write_kmip_object_to_file,
};
use cosmian_kms_crypto::crypto::wrap::unwrap_key_block;
use cosmian_logger::trace;
use crate::{
actions::kms::console,
cli_bail,
error::result::{KmsCliResult, KmsCliResultHelper},
};
#[derive(Parser, Default, Debug)]
#[clap(verbatim_doc_comment)]
pub struct UnwrapSecretDataOrKeyAction {
#[clap(required = true)]
pub(crate) key_file_in: PathBuf,
#[clap(required = false)]
pub(crate) key_file_out: Option<PathBuf>,
#[clap(
long = "unwrap-key-b64",
short = 'k',
required = false,
group = "unwrap"
)]
pub(crate) unwrap_key_b64: Option<String>,
#[clap(
long = "unwrap-key-id",
short = 'i',
required = false,
group = "unwrap"
)]
pub(crate) unwrap_key_id: Option<String>,
#[clap(
long = "unwrap-key-file",
short = 'f',
required = false,
group = "unwrap"
)]
pub(crate) unwrap_key_file: Option<PathBuf>,
}
impl UnwrapSecretDataOrKeyAction {
pub async fn run(&self, kms_rest_client: KmsClient) -> KmsCliResult<()> {
let mut object = read_object_from_json_ttlv_file(&self.key_file_in)?;
let object_type = object.object_type();
let unwrapping_key = if let Some(b64) = &self.unwrap_key_b64 {
trace!("unwrap using a base64 encoded key: {b64}");
let key_bytes = general_purpose::STANDARD
.decode(b64)
.with_context(|| "failed decoding the unwrap key")?;
create_symmetric_key_kmip_object(
&key_bytes,
&Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
..Default::default()
},
)?
} else if let Some(key_id) = &self.unwrap_key_id {
trace!("unwrap using the KMS server with the unique identifier of the unwrapping key");
export_object(&kms_rest_client, key_id, ExportObjectParams::default())
.await?
.1
} else if let Some(key_file) = &self.unwrap_key_file {
trace!("unwrap using a key file path");
read_object_from_json_ttlv_file(key_file)?
} else {
cli_bail!("one of the unwrapping options must be specified");
};
unwrap_key_block(object.key_block_mut()?, &unwrapping_key)?;
let output_file = self
.key_file_out
.as_ref()
.unwrap_or(&self.key_file_in)
.clone();
write_kmip_object_to_file(&object, &output_file)?;
let stdout = format!(
"The key of type {:?} in file {} was unwrapped in file: {}",
object_type,
self.key_file_in.display(),
&output_file.display()
);
console::Stdout::new(&stdout).write()?;
Ok(())
}
}