use cosmian_kms_client::{
cosmian_kmip::{
kmip_0::kmip_types::CryptographicUsageMask,
kmip_2_1::{
kmip_attributes::Attributes,
kmip_data_structures::{KeyBlock, KeyValue},
kmip_objects::{Object, ObjectType, SplitKey},
kmip_operations::{Get, Import, ImportResponse},
kmip_types::{CryptographicAlgorithm, KeyFormatType, SplitKeyMethod, UniqueIdentifier},
requests::create_symmetric_key_kmip_object,
},
},
kmip_2_1::extra::tagging::VENDOR_ID_COSMIAN,
};
use cosmian_logger::log_init;
use test_kms_server::start_default_test_kms_server;
use zeroize::Zeroizing;
use crate::error::result::KmsCliResult;
#[tokio::test]
async fn test_import_success_symmetric_key() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let client = ctx.get_owner_client();
let key_bytes = vec![0xAA; 32];
let attributes = Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
cryptographic_usage_mask: Some(
CryptographicUsageMask::Encrypt | CryptographicUsageMask::Decrypt,
),
object_type: Some(ObjectType::SymmetricKey),
..Default::default()
};
let object = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes, &attributes)?;
let import_request = Import {
unique_identifier: UniqueIdentifier::default(), object_type: ObjectType::SymmetricKey,
replace_existing: Some(false),
key_wrap_type: None,
attributes: attributes.clone(),
object,
};
let response: ImportResponse = client.import(import_request).await?;
assert!(!response.unique_identifier.to_string().is_empty());
let get_response = client
.get(Get {
unique_identifier: Some(response.unique_identifier.clone()),
..Default::default()
})
.await?;
assert_eq!(
get_response.object_type,
ObjectType::SymmetricKey,
"Retrieved object should be SymmetricKey"
);
Ok(())
}
#[tokio::test]
async fn test_import_error_object_already_exists() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let client = ctx.get_owner_client();
let key_bytes = vec![0xBB; 32];
let attributes = Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
cryptographic_usage_mask: Some(
CryptographicUsageMask::Encrypt | CryptographicUsageMask::Decrypt,
),
object_type: Some(ObjectType::SymmetricKey),
..Default::default()
};
let object1 = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes, &attributes)?;
let import_request1 = Import {
unique_identifier: "test-duplicate-uid-12345".into(),
object_type: ObjectType::SymmetricKey,
replace_existing: Some(false),
key_wrap_type: None,
attributes: attributes.clone(),
object: object1,
};
let response1: ImportResponse = client.import(import_request1).await?;
assert_eq!(
response1.unique_identifier.to_string(),
"test-duplicate-uid-12345"
);
let object2 = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes, &attributes)?;
let import_request2 = Import {
unique_identifier: "test-duplicate-uid-12345".into(),
object_type: ObjectType::SymmetricKey,
replace_existing: Some(false), key_wrap_type: None,
attributes: attributes.clone(),
object: object2,
};
let result = client.import(import_request2).await;
assert!(
result.is_err(),
"Import should fail when object already exists and replace_existing is false"
);
let error = result.unwrap_err();
let err_msg = error.to_string();
assert!(
err_msg.contains("Object_Already_Exists")
|| err_msg.contains("one or more objects already exist"),
"Expected Object_Already_Exists or 'one or more objects already exist' error, got: {error}"
);
Ok(())
}
#[tokio::test]
async fn test_import_success_replace_existing() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let client = ctx.get_owner_client();
let key_bytes1 = vec![0xCC; 32];
let attributes = Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
cryptographic_usage_mask: Some(
CryptographicUsageMask::Encrypt | CryptographicUsageMask::Decrypt,
),
object_type: Some(ObjectType::SymmetricKey),
..Default::default()
};
let object1 = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes1, &attributes)?;
let import_request1 = Import {
unique_identifier: "test-replace-uid-67890".into(),
object_type: ObjectType::SymmetricKey,
replace_existing: Some(false),
key_wrap_type: None,
attributes: attributes.clone(),
object: object1,
};
let _response1: ImportResponse = client.import(import_request1).await?;
let key_bytes2 = vec![0xDD; 32];
let object2 = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes2, &attributes)?;
let import_request2 = Import {
unique_identifier: "test-replace-uid-67890".into(),
object_type: ObjectType::SymmetricKey,
replace_existing: Some(true), key_wrap_type: None,
attributes: attributes.clone(),
object: object2,
};
let response2: ImportResponse = client.import(import_request2).await?;
assert_eq!(
response2.unique_identifier.to_string(),
"test-replace-uid-67890"
);
Ok(())
}
#[tokio::test]
async fn test_import_error_unsupported_object_type() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let client = ctx.get_owner_client();
let key_bytes = vec![0xEE; 32];
let key_block = KeyBlock {
key_format_type: KeyFormatType::Raw,
key_compression_type: None,
key_value: Some(KeyValue::ByteString(Zeroizing::new(key_bytes.clone()))),
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
key_wrapping_data: None,
};
let split_key = SplitKey {
split_key_parts: 3,
key_part_identifier: 1,
split_key_threshold: 2,
split_key_method: SplitKeyMethod::XOR,
prime_field_size: None,
key_block,
};
let object = Object::SplitKey(split_key);
let attributes = Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
object_type: Some(ObjectType::SplitKey),
..Default::default()
};
let import_request = Import {
unique_identifier: UniqueIdentifier::default(),
object_type: ObjectType::SplitKey,
replace_existing: Some(false),
key_wrap_type: None,
attributes,
object,
};
let result = client.import(import_request).await;
assert!(
result.is_err(),
"Import should fail for unsupported object type"
);
let error = result.unwrap_err();
let error_msg = error.to_string().to_lowercase();
assert!(
error_msg.contains("not") && (error_msg.contains("support") || error_msg.contains("split")),
"Error should indicate unsupported operation, got: {error}"
);
Ok(())
}
#[tokio::test]
async fn test_import_error_invalid_uid_reserved() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let client = ctx.get_owner_client();
let key_bytes = vec![0xFF; 32];
let attributes = Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
cryptographic_usage_mask: Some(
CryptographicUsageMask::Encrypt | CryptographicUsageMask::Decrypt,
),
object_type: Some(ObjectType::SymmetricKey),
..Default::default()
};
let object = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes, &attributes)?;
let import_request = Import {
unique_identifier: "[tag1]".into(), object_type: ObjectType::SymmetricKey,
replace_existing: Some(false),
key_wrap_type: None,
attributes,
object,
};
let result = client.import(import_request).await;
assert!(
result.is_err(),
"Import should fail for reserved UID pattern"
);
let error = result.unwrap_err();
let error_msg = error.to_string().to_lowercase();
assert!(
error_msg.contains("not supported") || error_msg.contains('['),
"Error should indicate invalid UID pattern, got: {error}"
);
Ok(())
}
#[tokio::test]
async fn test_import_sets_initial_date() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let client = ctx.get_owner_client();
let key_bytes = vec![0x11; 32];
let attributes = Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
cryptographic_usage_mask: Some(
CryptographicUsageMask::Encrypt | CryptographicUsageMask::Decrypt,
),
object_type: Some(ObjectType::SymmetricKey),
..Default::default()
};
let object = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes, &attributes)?;
let import_request = Import {
unique_identifier: UniqueIdentifier::default(),
object_type: ObjectType::SymmetricKey,
replace_existing: Some(false),
key_wrap_type: None,
attributes,
object,
};
let response: ImportResponse = client.import(import_request).await?;
let get_response = client
.get(Get {
unique_identifier: Some(response.unique_identifier.clone()),
..Get::default()
})
.await?;
let attrs = get_response.object.attributes()?;
assert!(
attrs.initial_date.is_some(),
"InitialDate should be set on imported object"
);
Ok(())
}
#[tokio::test]
async fn test_import_preserves_key_format_type() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let client = ctx.get_owner_client();
let key_bytes = vec![0x22; 32];
let mut attributes = Attributes {
cryptographic_algorithm: Some(CryptographicAlgorithm::AES),
cryptographic_length: Some(256),
cryptographic_usage_mask: Some(
CryptographicUsageMask::Encrypt | CryptographicUsageMask::Decrypt,
),
object_type: Some(ObjectType::SymmetricKey),
key_format_type: Some(KeyFormatType::TransparentSymmetricKey), ..Default::default()
};
let object = create_symmetric_key_kmip_object(VENDOR_ID_COSMIAN, &key_bytes, &attributes)?;
attributes.key_format_type = None;
let import_request = Import {
unique_identifier: UniqueIdentifier::default(),
object_type: ObjectType::SymmetricKey,
replace_existing: Some(false),
key_wrap_type: None,
attributes,
object,
};
let response: ImportResponse = client.import(import_request).await?;
let get_response = client
.get(Get {
unique_identifier: Some(response.unique_identifier.clone()),
..Get::default()
})
.await?;
let attrs = get_response.object.attributes()?;
assert_eq!(
attrs.key_format_type,
Some(KeyFormatType::TransparentSymmetricKey),
"KeyFormatType should be preserved from imported object"
);
Ok(())
}
#[tokio::test]
#[ignore = "Requires authentication setup"]
async fn test_import_error_permission_denied() -> KmsCliResult<()> {
log_init(None);
let ctx = start_default_test_kms_server().await;
let _client = ctx.get_owner_client();
Ok(())
}
#[tokio::test]
#[ignore = "Requires proper certificate DER data - see certificates module for full tests"]
async fn test_import_success_certificate() -> KmsCliResult<()> {
log_init(None);
let _ctx = start_default_test_kms_server().await;
Ok(())
}