use std::process::Command;
use assert_cmd::prelude::CommandCargoExt;
use cosmian_kms_cli_actions::actions::symmetric::keys::create_key::CreateKeyAction;
use tempfile::TempDir;
use test_kms_server::{
start_default_test_kms_server, start_default_test_kms_server_with_non_revocable_key_ids,
};
use uuid::Uuid;
#[cfg(feature = "non-fips")]
use crate::tests::cover_crypt::{
master_key_pair::create_cc_master_key_pair, user_decryption_keys::create_user_decryption_key,
};
#[cfg(feature = "non-fips")]
use crate::tests::elliptic_curve::create_key_pair::create_ec_key_pair;
use crate::{
config::CKMS_CONF_ENV,
error::{CosmianError, result::CosmianResult},
tests::{
PROG_NAME, save_kms_cli_config,
shared::{ExportKeyParams, export::export_key},
symmetric::create_key::create_symmetric_key,
utils::recover_cmd_logs,
},
};
pub(crate) fn revoke(
cli_conf_path: &str,
sub_command: &str,
key_id: &str,
revocation_reason: &str,
) -> CosmianResult<()> {
let args: Vec<String> = ["keys", "revoke", "--key-id", key_id, revocation_reason]
.iter()
.map(std::string::ToString::to_string)
.collect();
let mut cmd = Command::cargo_bin(PROG_NAME)?;
cmd.env(CKMS_CONF_ENV, cli_conf_path);
cmd.arg(sub_command).args(args);
let output = recover_cmd_logs(&mut cmd);
if output.status.success() {
return Ok(());
}
Err(CosmianError::Default(
std::str::from_utf8(&output.stderr)?.to_owned(),
))
}
pub(crate) fn assert_revoked(cli_conf_path: &str, key_id: &str) -> CosmianResult<()> {
let tmp_dir = TempDir::new()?;
let tmp_path = tmp_dir.path();
assert!(
export_key(ExportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: "ec".to_owned(),
key_id: key_id.to_owned(),
key_file: tmp_path.join("output.export").to_str().unwrap().to_string(),
..Default::default()
})
.is_err()
);
assert!(
export_key(ExportKeyParams {
cli_conf_path: cli_conf_path.to_string(),
sub_command: "ec".to_owned(),
key_id: key_id.to_owned(),
key_file: tmp_path.join("output.export").to_str().unwrap().to_string(),
allow_revoked: true,
..Default::default()
})
.is_ok()
);
Ok(())
}
#[tokio::test]
async fn test_revoke_symmetric_key() -> CosmianResult<()> {
let ctx = start_default_test_kms_server().await;
let (owner_client_conf_path, _) = save_kms_cli_config(ctx);
let key_id = create_symmetric_key(&owner_client_conf_path, CreateKeyAction::default())?;
revoke(&owner_client_conf_path, "sym", &key_id, "revocation test")?;
assert_revoked(&owner_client_conf_path, &key_id)
}
#[cfg(feature = "non-fips")]
#[tokio::test]
async fn test_revoke_ec_key() -> CosmianResult<()> {
let ctx = start_default_test_kms_server().await;
let (owner_client_conf_path, _) = save_kms_cli_config(ctx);
{
let (private_key_id, public_key_id) =
create_ec_key_pair(&owner_client_conf_path, "nist-p256", &[], false)?;
revoke(
&owner_client_conf_path,
"ec",
&private_key_id,
"revocation test",
)?;
assert_revoked(&owner_client_conf_path, &private_key_id)?;
assert_revoked(&owner_client_conf_path, &public_key_id)?;
}
{
let (private_key_id, public_key_id) =
create_ec_key_pair(&owner_client_conf_path, "nist-p256", &[], false)?;
revoke(
&owner_client_conf_path,
"ec",
&public_key_id,
"revocation test",
)?;
assert_revoked(&owner_client_conf_path, &private_key_id)?;
assert_revoked(&owner_client_conf_path, &public_key_id)?;
}
Ok(())
}
#[cfg(feature = "non-fips")]
#[tokio::test]
async fn test_revoke_cover_crypt() -> CosmianResult<()> {
let ctx = start_default_test_kms_server().await;
let (owner_client_conf_path, _) = save_kms_cli_config(ctx);
{
let (master_private_key_id, master_public_key_id) = create_cc_master_key_pair(
&owner_client_conf_path,
"--specification",
"../../../test_data/access_structure_specifications.json",
&[],
false,
)?;
let user_key_id_1 = create_user_decryption_key(
&owner_client_conf_path,
&master_private_key_id,
"(Department::MKG || Department::FIN) && Security Level::Top Secret",
&[],
false,
)?;
let user_key_id_2 = create_user_decryption_key(
&owner_client_conf_path,
&master_private_key_id,
"(Department::MKG || Department::FIN) && Security Level::Top Secret",
&[],
false,
)?;
revoke(
&owner_client_conf_path,
"cc",
&master_private_key_id,
"revocation test",
)?;
assert_revoked(&owner_client_conf_path, &master_private_key_id)?;
assert_revoked(&owner_client_conf_path, &master_public_key_id)?;
assert_revoked(&owner_client_conf_path, &user_key_id_1)?;
assert_revoked(&owner_client_conf_path, &user_key_id_2)?;
}
{
let (master_private_key_id, master_public_key_id) = create_cc_master_key_pair(
&owner_client_conf_path,
"--specification",
"../../../test_data/access_structure_specifications.json",
&[],
false,
)?;
let user_key_id_1 = create_user_decryption_key(
&owner_client_conf_path,
&master_private_key_id,
"(Department::MKG || Department::FIN) && Security Level::Top Secret",
&[],
false,
)?;
let user_key_id_2 = create_user_decryption_key(
&owner_client_conf_path,
&master_private_key_id,
"(Department::MKG || Department::FIN) && Security Level::Top Secret",
&[],
false,
)?;
revoke(
&owner_client_conf_path,
"cc",
&master_public_key_id,
"revocation test",
)?;
assert_revoked(&owner_client_conf_path, &master_private_key_id)?;
assert_revoked(&owner_client_conf_path, &master_public_key_id)?;
assert_revoked(&owner_client_conf_path, &user_key_id_1)?;
assert_revoked(&owner_client_conf_path, &user_key_id_2)?;
}
{
let (master_private_key_id, master_public_key_id) = create_cc_master_key_pair(
&owner_client_conf_path,
"--specification",
"../../../test_data/access_structure_specifications.json",
&[],
false,
)?;
let user_key_id_1 = create_user_decryption_key(
&owner_client_conf_path,
&master_private_key_id,
"(Department::MKG || Department::FIN) && Security Level::Top Secret",
&[],
false,
)?;
let user_key_id_2 = create_user_decryption_key(
&owner_client_conf_path,
&master_private_key_id,
"(Department::MKG || Department::FIN) && Security Level::Top Secret",
&[],
false,
)?;
revoke(
&owner_client_conf_path,
"cc",
&user_key_id_1,
"revocation test",
)?;
assert_revoked(&owner_client_conf_path, &user_key_id_1)?;
let tmp_dir = TempDir::new()?;
let tmp_path = tmp_dir.path();
assert!(
export_key(ExportKeyParams {
cli_conf_path: owner_client_conf_path.clone(),
sub_command: "cc".to_owned(),
key_id: master_private_key_id,
key_file: tmp_path.join("output.export").to_str().unwrap().to_string(),
..Default::default()
})
.is_ok()
);
assert!(
export_key(ExportKeyParams {
cli_conf_path: owner_client_conf_path.clone(),
sub_command: "cc".to_owned(),
key_id: master_public_key_id,
key_file: tmp_path.join("output.export").to_str().unwrap().to_string(),
..Default::default()
})
.is_ok()
);
assert!(
export_key(ExportKeyParams {
cli_conf_path: owner_client_conf_path,
sub_command: "cc".to_owned(),
key_id: user_key_id_2,
key_file: tmp_path.join("output.export").to_str().unwrap().to_string(),
..Default::default()
})
.is_ok()
);
}
Ok(())
}
#[tokio::test]
async fn test_non_revocable_symmetric_key() -> CosmianResult<()> {
let non_revocable_key = Uuid::new_v4().to_string();
let ctx = start_default_test_kms_server_with_non_revocable_key_ids(Some(vec![
non_revocable_key.clone(),
Uuid::new_v4().to_string(),
]))
.await;
let (owner_client_conf_path, _) = save_kms_cli_config(ctx);
let key_id = create_symmetric_key(
&owner_client_conf_path,
CreateKeyAction {
key_id: Some(non_revocable_key.clone()),
..Default::default()
},
)?;
assert_eq!(key_id, non_revocable_key);
revoke(&owner_client_conf_path, "sym", &key_id, "revocation test")?;
let tmp_dir = TempDir::new()?;
let tmp_path = tmp_dir.path();
assert!(
export_key(ExportKeyParams {
cli_conf_path: owner_client_conf_path,
sub_command: "ec".to_owned(),
key_id,
key_file: tmp_path.join("output.export").to_str().unwrap().to_string(),
..Default::default()
})
.is_ok()
);
Ok(())
}