use async_trait::async_trait;
use cosmian_kmip::kmip_2_1::{
kmip_attributes::Attributes, kmip_objects::ObjectType, kmip_types::CryptographicAlgorithm,
};
use zeroize::Zeroizing;
use crate::{
CryptoAlgorithm, InterfaceError, InterfaceResult, KeyMetadata, KeyType, SigningAlgorithm,
crypto_oracle::EncryptedContent,
};
pub enum HsmKeyAlgorithm {
AES,
}
pub enum HsmKeypairAlgorithm {
RSA,
}
#[derive(Clone, PartialEq, Eq)]
pub enum HsmObjectFilter {
Any,
AesKey,
RsaKey,
RsaPrivateKey,
RsaPublicKey,
}
impl TryFrom<&Attributes> for HsmObjectFilter {
type Error = InterfaceError;
fn try_from(researched_attributes: &Attributes) -> InterfaceResult<Self> {
let mut object_filter = if let Some(cryptographic_algorithm) =
researched_attributes.cryptographic_algorithm
{
match cryptographic_algorithm {
CryptographicAlgorithm::AES => Self::AesKey,
CryptographicAlgorithm::RSA => Self::RsaKey,
_ => {
return Err(InterfaceError::Default(format!(
"Unsupported cryptographic algorithm for HSMs: {cryptographic_algorithm}"
)));
}
}
} else {
Self::Any
};
if let Some(object_type) = researched_attributes.object_type {
object_filter = match object_type {
ObjectType::SymmetricKey => {
if object_filter == Self::RsaKey {
return Err(InterfaceError::Default(
"Incompatible object type: SymmetricKey with RSA".to_owned(),
));
}
Self::AesKey
}
ObjectType::PublicKey => {
if object_filter == Self::AesKey {
return Err(InterfaceError::Default(
"Incompatible object type: PublicKey with AES".to_owned(),
));
}
Self::RsaPublicKey
}
ObjectType::PrivateKey => {
if object_filter == Self::AesKey {
return Err(InterfaceError::Default(
"Incompatible object type: PrivateKey with AES".to_owned(),
));
}
Self::RsaPrivateKey
}
_ => {
return Err(InterfaceError::Default(format!(
"Unsupported object type for HSMs: {object_type}"
)));
}
};
}
Ok(object_filter)
}
}
#[derive(Debug)]
pub struct RsaPrivateKeyMaterial {
pub modulus: Vec<u8>,
pub public_exponent: Vec<u8>,
pub private_exponent: Zeroizing<Vec<u8>>,
pub prime_1: Zeroizing<Vec<u8>>,
pub prime_2: Zeroizing<Vec<u8>>,
pub exponent_1: Zeroizing<Vec<u8>>,
pub exponent_2: Zeroizing<Vec<u8>>,
pub coefficient: Zeroizing<Vec<u8>>,
}
#[derive(Debug)]
pub struct RsaPublicKeyMaterial {
pub modulus: Vec<u8>,
pub public_exponent: Vec<u8>,
}
#[derive(Debug)]
pub enum KeyMaterial {
AesKey(Zeroizing<Vec<u8>>),
RsaPrivateKey(RsaPrivateKeyMaterial),
RsaPublicKey(RsaPublicKeyMaterial),
}
#[derive(Debug)]
pub struct HsmObject {
key_material: KeyMaterial,
id: String,
}
impl HsmObject {
#[must_use]
pub const fn new(key_material: KeyMaterial, label: String) -> Self {
Self {
key_material,
id: label,
}
}
#[must_use]
pub const fn key_material(&self) -> &KeyMaterial {
&self.key_material
}
#[must_use]
pub fn id(&self) -> &str {
&self.id
}
}
#[async_trait]
pub trait HSM: Send + Sync {
async fn get_available_slot_list(&self) -> InterfaceResult<Vec<usize>>;
async fn get_supported_algorithms(
&self,
slot_id: usize,
) -> InterfaceResult<Vec<CryptoAlgorithm>>;
async fn create_key(
&self,
slot_id: usize,
id: &[u8],
algorithm: HsmKeyAlgorithm,
key_length_in_bits: usize,
sensitive: bool,
) -> InterfaceResult<()>;
async fn create_keypair(
&self,
slot_id: usize,
sk_id: &[u8],
pk_id: &[u8],
algorithm: HsmKeypairAlgorithm,
key_length_in_bits: usize,
sensitive: bool,
) -> InterfaceResult<()>;
async fn export(&self, slot_id: usize, object_id: &[u8]) -> InterfaceResult<Option<HsmObject>>;
async fn delete(&self, slot_id: usize, object_id: &[u8]) -> InterfaceResult<()>;
async fn find(
&self,
slot_id: usize,
object_filter: HsmObjectFilter,
) -> InterfaceResult<Vec<Vec<u8>>>;
async fn encrypt(
&self,
slot_id: usize,
key_id: &[u8],
algorithm: CryptoAlgorithm,
data: &[u8],
) -> InterfaceResult<EncryptedContent>;
async fn decrypt(
&self,
slot_id: usize,
key_id: &[u8],
algorithm: CryptoAlgorithm,
data: &[u8],
) -> InterfaceResult<Zeroizing<Vec<u8>>>;
async fn get_key_type(&self, slot_id: usize, key_id: &[u8])
-> InterfaceResult<Option<KeyType>>;
async fn get_key_metadata(
&self,
slot_id: usize,
key_id: &[u8],
) -> InterfaceResult<Option<KeyMetadata>>;
async fn sign(
&self,
slot_id: usize,
key_id: &[u8],
algorithm: SigningAlgorithm,
data: &[u8],
) -> InterfaceResult<Vec<u8>>;
async fn generate_random(&self, slot_id: usize, len: usize) -> InterfaceResult<Vec<u8>>;
async fn seed_random(&self, slot_id: usize, seed: &[u8]) -> InterfaceResult<()>;
fn hsm_lib(&self) -> Option<&dyn std::any::Any>;
}