#[cfg(feature = "non-fips")]
use cosmian_kms_cli_actions::reexport::cosmian_kms_crypto::crypto::elliptic_curves::operation::create_x25519_key_pair;
use cosmian_kms_cli_actions::{
actions::symmetric::keys::create_key::CreateKeyAction,
reexport::{
cosmian_kms_client::{
cosmian_kmip::kmip_2_1::{
kmip_objects::Object,
kmip_types::{CryptographicAlgorithm, LinkType, UniqueIdentifier, WrappingMethod},
},
kmip_2_1::{
extra::VENDOR_ID_COSMIAN, kmip_attributes::Attributes,
kmip_data_structures::KeyValue, requests::create_symmetric_key_kmip_object,
},
read_object_from_json_ttlv_file,
reexport::cosmian_kms_client_utils::import_utils::KeyUsage,
write_kmip_object_to_file,
},
cosmian_kms_crypto::{
crypto::wrap::unwrap_key_block,
reexport::cosmian_crypto_core::{
CsRng,
reexport::rand_core::{RngCore, SeedableRng},
},
},
},
};
use cosmian_logger::{debug, trace};
use tempfile::TempDir;
use test_kms_server::start_default_test_kms_server;
use super::ExportKeyParams;
use crate::{
error::result::CosmianResult,
tests::{
cover_crypt::master_key_pair::create_cc_master_key_pair,
elliptic_curve, save_kms_cli_config,
shared::{ImportKeyParams, export::export_key, import::import_key},
symmetric::create_key::create_symmetric_key,
},
};
#[tokio::test]
pub(crate) async fn test_import_export_wrap_rfc_5649() -> CosmianResult<()> {
let tmp_dir = TempDir::new()?;
let tmp_path = tmp_dir.path();
let ctx = start_default_test_kms_server().await;
let (owner_client_conf_path, _) = save_kms_cli_config(ctx);
let wrap_key_path = tmp_path.join("wrap.key");
let mut rng = CsRng::from_entropy();
let mut wrap_key_bytes = vec![0; 32];
rng.fill_bytes(&mut wrap_key_bytes);
let wrap_key = create_symmetric_key_kmip_object(
VENDOR_ID_COSMIAN,
&wrap_key_bytes,
&Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
..Default::default()
},
)?;
write_kmip_object_to_file(&wrap_key, &wrap_key_path)?;
trace!("importing wrapping key");
let wrap_key_uid = import_key(ImportKeyParams {
cli_conf_path: owner_client_conf_path.clone(),
sub_command: "sym".to_string(),
key_file: wrap_key_path.to_str().unwrap().to_string(),
..Default::default()
})?;
let (private_key_id, _public_key_id) = create_cc_master_key_pair(
&owner_client_conf_path,
"--specification",
"../../../test_data/access_structure_specifications.json",
&[],
false,
)?;
test_import_export_wrap_private_key(
&owner_client_conf_path,
"cc",
&private_key_id,
&wrap_key_uid,
&wrap_key,
)?;
let (private_key_id, _public_key_id) = elliptic_curve::create_key_pair::create_ec_key_pair(
&owner_client_conf_path,
"nist-p256",
&[],
false,
)?;
test_import_export_wrap_private_key(
&owner_client_conf_path,
"ec",
&private_key_id,
&wrap_key_uid,
&wrap_key,
)?;
let key_id = create_symmetric_key(&owner_client_conf_path, CreateKeyAction::default())?;
test_import_export_wrap_private_key(
&owner_client_conf_path,
"sym",
&key_id,
&wrap_key_uid,
&wrap_key,
)?;
Ok(())
}
#[cfg(feature = "non-fips")]
#[tokio::test]
pub(crate) async fn test_import_export_wrap_ecies() -> CosmianResult<()> {
use cosmian_kms_cli_actions::reexport::cosmian_kms_client::kmip_0::kmip_types::CryptographicUsageMask;
cosmian_logger::log_init(None);
let tmp_dir = TempDir::new()?;
let tmp_path = tmp_dir.path();
let ctx = start_default_test_kms_server().await;
let (owner_client_conf_path, _) = save_kms_cli_config(ctx);
let wrap_private_key_uid = "wrap_private_key_uid";
let wrap_public_key_uid = "wrap_public_key_uid";
let wrap_key_pair = create_x25519_key_pair(
VENDOR_ID_COSMIAN,
wrap_private_key_uid,
wrap_public_key_uid,
&CryptographicAlgorithm::EC,
Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::EC),
..Default::default()
},
Some(Attributes {
cryptographic_usage_mask: Some(
CryptographicUsageMask::Decrypt | CryptographicUsageMask::UnwrapKey,
),
..Default::default()
}),
Some(Attributes {
cryptographic_usage_mask: Some(
CryptographicUsageMask::Encrypt | CryptographicUsageMask::WrapKey,
),
..Default::default()
}),
)?;
let wrap_private_key_path = tmp_path.join("wrap.private.key");
write_kmip_object_to_file(wrap_key_pair.private_key(), &wrap_private_key_path)?;
import_key(ImportKeyParams {
cli_conf_path: owner_client_conf_path.clone(),
sub_command: "ec".to_string(),
key_file: wrap_private_key_path.to_str().unwrap().to_string(),
key_id: Some(wrap_private_key_uid.to_string()),
replace_existing: true,
..Default::default()
})?;
let wrap_public_key_path = tmp_path.join("wrap.public.key");
write_kmip_object_to_file(wrap_key_pair.public_key(), &wrap_public_key_path)?;
import_key(ImportKeyParams {
cli_conf_path: owner_client_conf_path.clone(),
sub_command: "ec".to_string(),
key_file: wrap_public_key_path.to_str().unwrap().to_string(),
key_id: Some(wrap_public_key_uid.to_string()),
replace_existing: true,
..Default::default()
})?;
let (private_key_id, _public_key_id) = create_cc_master_key_pair(
&owner_client_conf_path,
"--specification",
"../../../test_data/access_structure_specifications.json",
&[],
false,
)?;
test_import_export_wrap_private_key(
&owner_client_conf_path,
"cc",
&private_key_id,
wrap_public_key_uid,
wrap_key_pair.private_key(),
)?;
debug!("testing EC keys");
let (private_key_id, _public_key_id) = elliptic_curve::create_key_pair::create_ec_key_pair(
&owner_client_conf_path,
"nist-p256",
&[],
false,
)?;
test_import_export_wrap_private_key(
&owner_client_conf_path,
"ec",
&private_key_id,
wrap_public_key_uid,
wrap_key_pair.private_key(),
)?;
debug!("testing symmetric keys");
let key_id = create_symmetric_key(&owner_client_conf_path, CreateKeyAction::default())?;
test_import_export_wrap_private_key(
&owner_client_conf_path,
"sym",
&key_id,
wrap_public_key_uid,
wrap_key_pair.private_key(),
)?;
Ok(())
}
fn test_import_export_wrap_private_key(
cli_conf_path: &str,
sub_command: &str,
private_key_id: &str,
wrapping_key_uid: &str,
unwrapping_key: &Object,
) -> CosmianResult<()> {
let tmp_dir = TempDir::new()?;
let tmp_path = tmp_dir.path();
let private_key_file = tmp_path.join("master_private.key");
let export_params = ExportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: sub_command.to_string(),
key_id: private_key_id.to_string(),
key_file: private_key_file.to_str().unwrap().to_string(),
..Default::default()
};
export_key(export_params)?;
let private_key = read_object_from_json_ttlv_file(&private_key_file)?;
let wrapped_private_key_file = tmp_path.join("wrapped_master_private.key");
export_key(ExportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: sub_command.to_string(),
key_id: private_key_id.to_string(),
key_file: wrapped_private_key_file.to_str().unwrap().to_string(),
wrap_key_id: Some(wrapping_key_uid.to_string()),
..Default::default()
})?;
{
let mut wrapped_private_key = read_object_from_json_ttlv_file(&wrapped_private_key_file)?;
let wrapped_key_wrapping_data = wrapped_private_key.key_wrapping_data().unwrap();
assert_eq!(
wrapped_key_wrapping_data.wrapping_method,
WrappingMethod::Encrypt
);
assert_eq!(
wrapped_key_wrapping_data
.encryption_key_information
.clone()
.unwrap()
.unique_identifier,
UniqueIdentifier::TextString(wrapping_key_uid.to_owned())
);
assert!(
wrapped_key_wrapping_data
.encryption_key_information
.clone()
.unwrap()
.cryptographic_parameters
.is_none()
);
unwrap_key_block(wrapped_private_key.key_block_mut()?, unwrapping_key)?;
assert!(wrapped_private_key.key_block()?.key_value == private_key.key_block()?.key_value);
}
{
let unwrapped_key_id = import_key(ImportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: sub_command.to_string(),
key_file: wrapped_private_key_file.to_str().unwrap().to_string(),
unwrap: true,
replace_existing: true,
..Default::default()
})?;
let re_exported_key_file = tmp_path.join("re_exported_master_private.key");
export_key(ExportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: sub_command.to_string(),
key_id: unwrapped_key_id,
key_file: re_exported_key_file.to_str().unwrap().to_string(),
..Default::default()
})?;
let re_exported_key = read_object_from_json_ttlv_file(&re_exported_key_file)?;
let re_exported_key_material = {
let Some(KeyValue::Structure { key_material, .. }) =
&re_exported_key.key_block()?.key_value
else {
panic!("Key value is not a structure");
};
key_material
};
let private_key_key_material = {
let Some(KeyValue::Structure { key_material, .. }) =
&private_key.key_block()?.key_value
else {
panic!("Key value is not a structure");
};
key_material
};
assert_eq!(re_exported_key_material, private_key_key_material);
assert_eq!(
re_exported_key
.key_block()?
.attributes()?
.get_link(LinkType::PublicKeyLink),
private_key
.key_block()?
.attributes()?
.get_link(LinkType::PublicKeyLink)
);
assert!(re_exported_key.key_wrapping_data().is_none());
}
{
let wrapped_key_id = import_key(ImportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: sub_command.to_string(),
key_file: wrapped_private_key_file.to_str().unwrap().to_string(),
key_usage_vec: Some(vec![KeyUsage::Unrestricted]),
replace_existing: true,
..Default::default()
})?;
let exported_unwrapped_key_file = tmp_path.join("exported_unwrapped_master_private.key");
export_key(ExportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: sub_command.to_string(),
key_id: wrapped_key_id,
key_file: exported_unwrapped_key_file.to_str().unwrap().to_string(),
unwrap: true,
..Default::default()
})?;
let mut exported_unwrapped_key =
read_object_from_json_ttlv_file(&exported_unwrapped_key_file)?;
let exp_attrs = exported_unwrapped_key.key_block_mut()?.attributes_mut()?;
exp_attrs
.unique_identifier
.clone_from(&private_key.key_block()?.attributes()?.unique_identifier);
exp_attrs.fresh = None;
assert_eq!(
exported_unwrapped_key.key_block()?.key_value,
private_key.key_block()?.key_value
);
assert!(exported_unwrapped_key.key_wrapping_data().is_none());
}
Ok(())
}