use async_trait::async_trait;
use std::{
collections::HashMap,
sync::atomic::{AtomicBool, Ordering},
sync::Arc,
time::{SystemTime, UNIX_EPOCH},
};
use zeroize::Zeroize;
use bitcoin::{
secp256k1::{Message, PublicKey, Secp256k1, SecretKey},
Network,
};
use rand::{rngs::OsRng, Rng};
use crate::security::hsm::{
error::HsmError,
provider::{
EcCurve, HsmOperation, HsmProvider, HsmProviderStatus, HsmRequest, HsmResponse,
KeyGenParams, KeyInfo, KeyPair, KeyType, KeyUsage, SigningAlgorithm,
},
types::{DeleteKeyParams, GetKeyParams, SignParams, VerifyParams},
};
use crate::security::hsm::audit::AuditLogger;
use crate::security::hsm::config::SoftHsmConfig;
use crate::security::hsm::error::{AuditEventResult, AuditEventSeverity, AuditEventType};
use chrono::{DateTime, Utc};
use sha2::Digest;
use sha2::{Sha256, Sha384};
use tokio::sync::Mutex;
#[derive(Clone)]
struct SecureString {
data: Arc<Mutex<Vec<u8>>>,
}
impl SecureString {
fn from(data: Vec<u8>) -> Self {
Self {
data: Arc::new(Mutex::new(data)),
}
}
async fn lock(&self) -> tokio::sync::MutexGuard<'_, Vec<u8>> {
self.data.lock().await
}
}
impl Drop for SecureString {
fn drop(&mut self) {
if let Ok(mut data) = self.data.try_lock() {
data.fill(0);
}
}
}
impl zeroize::Zeroize for SecureString {
fn zeroize(&mut self) {
if let Ok(mut data) = self.data.try_lock() {
data.zeroize();
}
}
}
#[derive(Clone)]
struct SecureKey {
key_data: SecureString,
info: KeyInfo,
created_at: u64,
last_used: Option<u64>,
used: Arc<AtomicBool>,
}
impl std::fmt::Debug for SecureKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SecureKey")
.field("key_id", &self.info.id)
.field("key_type", &self.info.key_type)
.field("created_at", &self.created_at)
.field("last_used", &self.last_used)
.field("used", &self.used.load(Ordering::Relaxed))
.finish()
}
}
impl Drop for SecureKey {
fn drop(&mut self) {
self.key_data.zeroize();
}
}
#[derive(Debug)]
pub struct SoftwareHsmProvider {
keys: Mutex<HashMap<String, SecureKey>>,
secp: Secp256k1<bitcoin::secp256k1::All>,
audit_logger: Arc<AuditLogger>,
}
impl SoftwareHsmProvider {
pub async fn new(
_config: SoftHsmConfig,
_network: Network,
audit_logger: Arc<AuditLogger>,
) -> Result<Self, HsmError> {
let secp = Secp256k1::new();
let provider = Self {
keys: Mutex::new(HashMap::new()),
secp,
audit_logger,
};
provider
.audit_logger
.log(
crate::security::hsm::error::AuditEventType::Initialization,
crate::security::hsm::error::AuditEventResult::Success,
crate::security::hsm::error::AuditEventSeverity::Info,
"HSM provider initialized successfully",
)
.await?;
Ok(provider)
}
fn generate_key_id(&self) -> String {
let mut rng = OsRng;
let id: [u8; 16] = rng.gen();
hex::encode(id)
}
async fn store_key(
&self,
key_id: String,
secret: SecureString,
_public_key: Vec<u8>,
key_type: KeyType,
_usage: KeyUsage, ) -> Result<KeyInfo, HsmError> {
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| HsmError::InternalError("System time is before UNIX_EPOCH".into()))?
.as_secs();
let key_info = KeyInfo {
id: key_id.clone(),
label: Some(key_id.clone()),
key_type: key_type.clone(),
extractable: false, usages: vec![KeyUsage::Sign, KeyUsage::Verify],
created_at: DateTime::from_timestamp(now as i64, 0).unwrap_or_else(|| Utc::now()),
expires_at: None,
attributes: HashMap::new(),
};
let secure_key = SecureKey {
key_data: secret,
info: key_info.clone(),
created_at: now,
last_used: None,
used: Arc::new(AtomicBool::new(false)),
};
let mut keys = self.keys.lock().await;
keys.insert(key_id, secure_key);
self.audit_logger
.log_event(
AuditEventType::KeyGeneration,
AuditEventResult::Success,
AuditEventSeverity::Info,
&format!("Stored new {:?} key", key_type),
)
.await?;
Ok(key_info)
}
async fn generate_key(&self, params: KeyGenParams) -> Result<(KeyPair, KeyInfo), HsmError> {
use crate::security::hsm::provider::{EcCurve, KeyType};
use chrono::Utc;
let key_id = self.generate_key_id();
let (secret, public_key) = match params.key_type {
KeyType::Ec {
curve: EcCurve::Secp256k1,
} => {
let (secret_key, public_key) = self.secp.generate_keypair(&mut OsRng);
let secret_bytes = secret_key.secret_bytes();
let public_bytes = public_key.serialize_uncompressed().to_vec();
(SecureString::from(secret_bytes.to_vec()), public_bytes)
}
_ => {
return Err(HsmError::UnsupportedOperation(
"Only secp256k1 is currently supported".to_string(),
))
}
};
let key_info = KeyInfo {
id: key_id.clone(),
label: Some(key_id.clone()),
key_type: params.key_type.clone(),
extractable: false,
usages: vec![KeyUsage::Sign, KeyUsage::Verify],
created_at: Utc::now(),
expires_at: None,
attributes: HashMap::new(),
};
self.store_key(
key_id.clone(),
secret,
public_key.clone(),
params.key_type.clone(),
*params.usages.first().unwrap_or(&KeyUsage::Sign),
)
.await?;
let key_pair = KeyPair {
id: key_id.clone(),
key_type: params.key_type,
public_key: public_key.clone(),
private_key_handle: key_id.clone(),
};
Ok((key_pair, key_info))
}
async fn sign(
&self,
key_id: &str,
algorithm: SigningAlgorithm, data: &[u8],
) -> Result<Vec<u8>, HsmError> {
let keys = self.keys.lock().await;
let key = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
let secret_key = {
let key_data = key.key_data.lock().await;
key_data.clone()
};
match algorithm {
SigningAlgorithm::EcdsaSha256 => {
let secret_bytes = &*secret_key; let secret_key = SecretKey::from_slice(secret_bytes)
.map_err(|e| HsmError::SigningError(format!("Invalid key data: {}", e)))?;
let mut hasher = Sha256::new();
hasher.update(data);
let message_hash = hasher.finalize();
let message = bitcoin::secp256k1::Message::from_digest_slice(&message_hash)
.map_err(|e| HsmError::SigningError(format!("Invalid message hash: {}", e)))?;
let signature = self.secp.sign_ecdsa(&message, &secret_key);
Ok(signature.serialize_der().to_vec())
}
SigningAlgorithm::EcdsaSha384 => {
let secret_bytes = &*secret_key; let secret_key = SecretKey::from_slice(secret_bytes)
.map_err(|e| HsmError::SigningError(format!("Invalid key data: {}", e)))?;
let mut hasher = Sha384::new();
hasher.update(data);
let message_hash = hasher.finalize();
let truncated_hash = &message_hash[..32];
let message = bitcoin::secp256k1::Message::from_digest_slice(truncated_hash)
.map_err(|e| HsmError::SigningError(format!("Invalid message hash: {}", e)))?;
let signature = self.secp.sign_ecdsa(&message, &secret_key);
Ok(signature.serialize_der().to_vec())
}
_ => Err(HsmError::UnsupportedOperation(format!(
"Unsupported signing algorithm: {:?}",
algorithm
))),
}
}
async fn verify(
&self,
key_id: &str,
algorithm: SigningAlgorithm,
data: &[u8],
signature: &[u8],
) -> Result<bool, HsmError> {
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
match algorithm {
SigningAlgorithm::EcdsaSha256 => {
match key_info.info.key_type {
KeyType::Ec {
curve: EcCurve::Secp256k1,
} => {
let mut hasher = Sha256::new();
hasher.update(data);
let message_hash = hasher.finalize();
let pubkey_bytes = self.export_public_key(key_id).await?;
let public_key = PublicKey::from_slice(&pubkey_bytes).map_err(|e| {
HsmError::VerificationError(format!("Invalid public key data: {}", e))
})?;
let sig = bitcoin::secp256k1::ecdsa::Signature::from_der(signature)
.map_err(|e| {
HsmError::VerificationError(format!(
"Invalid signature format: {}",
e
))
})?;
let message = Message::from_digest_slice(&message_hash).map_err(|e| {
HsmError::VerificationError(format!("Invalid message hash: {}", e))
})?;
match self.secp.verify_ecdsa(&message, &sig, &public_key) {
Ok(()) => Ok(true),
Err(_) => Ok(false),
}
}
_ => Err(HsmError::UnsupportedOperation(
"Unsupported curve for ECDSA verification".to_string(),
)),
}
}
_ => Err(HsmError::UnsupportedOperation(
"Unsupported signing algorithm".to_string(),
)),
}
}
async fn export_public_key(&self, key_id: &str) -> Result<Vec<u8>, HsmError> {
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
match key_info.info.key_type {
KeyType::Ec {
curve: EcCurve::Secp256k1,
} => {
let secret_key = key_info.key_data.lock().await;
let secret_key = SecretKey::from_slice(&*secret_key).map_err(|e| {
HsmError::KeyGenerationError(format!("Invalid key data: {}", e))
})?;
let public_key = PublicKey::from_secret_key(&self.secp, &secret_key);
Ok(public_key.serialize().to_vec())
}
_ => Err(HsmError::UnsupportedKeyType),
}
}
pub async fn delete_key(&self, key_id: &str) -> Result<(), HsmError> {
let mut keys = self.keys.lock().await;
if !keys.contains_key(key_id) {
return Err(HsmError::KeyNotFound(key_id.to_string()));
}
keys.remove(key_id);
self.audit_logger
.log_event(
crate::security::hsm::error::AuditEventType::KeyDeletion,
crate::security::hsm::error::AuditEventResult::Success,
crate::security::hsm::error::AuditEventSeverity::Info,
&format!("Key {} deleted successfully", key_id),
)
.await?;
Ok(())
}
}
#[async_trait]
impl HsmProvider for SoftwareHsmProvider {
async fn initialize(&self) -> Result<(), HsmError> {
Ok(())
}
async fn generate_key(&self, params: KeyGenParams) -> Result<(KeyPair, KeyInfo), HsmError> {
let key_id = params.id.clone().unwrap_or_else(|| self.generate_key_id());
let key_type = params.key_type.clone(); let (secret, public_key) = match key_type {
KeyType::Ec {
curve: EcCurve::Secp256k1,
} => {
let (secret_key, public_key) = self.secp.generate_keypair(&mut OsRng);
(
SecureString::from(secret_key[..].to_vec()),
public_key.serialize().to_vec(),
)
}
_ => {
return Err(HsmError::UnsupportedKeyType);
}
};
let key_info = KeyInfo {
id: key_id.clone(),
label: params.label.clone(),
key_type: key_type.clone(),
extractable: params.extractable,
usages: params.usages.clone(),
created_at: Utc::now(),
expires_at: params.expires_at,
attributes: params.attributes.clone(),
};
self.store_key(
key_id.clone(),
secret,
public_key.clone(),
key_type.clone(),
*params.usages.first().unwrap_or(&KeyUsage::Sign),
)
.await?;
let key_pair = KeyPair {
id: key_id.clone(),
key_type: key_type,
public_key: public_key.clone(),
private_key_handle: key_id,
};
Ok((key_pair, key_info))
}
async fn sign(
&self,
key_id: &str,
algorithm: SigningAlgorithm,
data: &[u8],
) -> Result<Vec<u8>, HsmError> {
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
match algorithm {
SigningAlgorithm::EcdsaSha256 => {
let key_data = key_info.key_data.lock().await;
let secret_bytes =
hex::decode(&*String::from_utf8_lossy(&key_data)).map_err(|e| {
HsmError::InvalidKeyData(format!("Failed to decode key: {}", e))
})?;
let secret_key = SecretKey::from_slice(&secret_bytes)
.map_err(|e| HsmError::InvalidKeyData(format!("Invalid secret key: {}", e)))?;
let mut hasher = Sha256::new();
hasher.update(data);
let message_hash = hasher.finalize();
let message = Message::from_digest_slice(&message_hash)
.map_err(|e| HsmError::SigningError(format!("Invalid message: {}", e)))?;
let signature = self.secp.sign_ecdsa(&message, &secret_key);
Ok(signature.serialize_compact().to_vec())
}
_ => Err(HsmError::UnsupportedOperation(
"Only ECDSA SHA-256 is supported".to_string(),
)),
}
}
async fn verify(
&self,
key_id: &str,
algorithm: SigningAlgorithm,
data: &[u8],
signature: &[u8],
) -> Result<bool, HsmError> {
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
match algorithm {
SigningAlgorithm::EcdsaSha256 => {
match key_info.info.key_type {
KeyType::Ec {
curve: EcCurve::Secp256k1,
} => {
let mut hasher = Sha256::new();
hasher.update(data);
let message_hash = hasher.finalize();
let pubkey_bytes = self.export_public_key(key_id).await?;
let public_key = PublicKey::from_slice(&pubkey_bytes).map_err(|e| {
HsmError::VerificationError(format!("Invalid public key data: {}", e))
})?;
let sig =
secp256k1::ecdsa::Signature::from_compact(signature).map_err(|e| {
HsmError::VerificationError(format!("Invalid signature: {}", e))
})?;
let message = Message::from_digest_slice(&message_hash).map_err(|e| {
HsmError::VerificationError(format!("Invalid message: {}", e))
})?;
Ok(self.secp.verify_ecdsa(&message, &sig, &public_key).is_ok())
}
_ => Err(HsmError::UnsupportedKeyType),
}
}
_ => Err(HsmError::UnsupportedOperation(
"Only ECDSA SHA-256 is supported".to_string(),
)),
}
}
async fn export_public_key(&self, key_id: &str) -> Result<Vec<u8>, HsmError> {
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(key_id.to_string()))?;
match key_info.info.key_type {
KeyType::Ec {
curve: EcCurve::Secp256k1,
} => {
let key_data = key_info.key_data.lock().await;
let secret_bytes =
hex::decode(&*String::from_utf8_lossy(&key_data)).map_err(|e| {
HsmError::InvalidKeyData(format!("Failed to decode key: {}", e))
})?;
let secret_key = SecretKey::from_slice(&secret_bytes).map_err(|e| {
HsmError::KeyGenerationError(format!("Invalid key data: {}", e))
})?;
let public_key = PublicKey::from_secret_key(&self.secp, &secret_key);
Ok(public_key.serialize().to_vec())
}
_ => Err(HsmError::UnsupportedKeyType),
}
}
async fn list_keys(&self) -> Result<Vec<KeyInfo>, HsmError> {
let keys = self.keys.lock().await;
Ok(keys.values().map(|k| k.info.clone()).collect())
}
async fn delete_key(&self, key_id: &str) -> Result<(), HsmError> {
self.delete_key(key_id).await
}
async fn get_status(&self) -> Result<HsmProviderStatus, HsmError> {
Ok(HsmProviderStatus::Ready)
}
async fn close(&self) -> Result<(), HsmError> {
let mut keys = self.keys.lock().await;
keys.clear();
Ok(())
}
async fn execute_operation(&self, request: HsmRequest) -> Result<HsmResponse, HsmError> {
match request.operation {
HsmOperation::GenerateKey => {
let params: KeyGenParams =
serde_json::from_value(request.parameters).map_err(|e| {
HsmError::InvalidParameters(format!(
"Invalid key generation parameters: {}",
e
))
})?;
let (key_pair, _key_info) = self.generate_key(params).await?;
Ok(HsmResponse::success(
request.id,
Some(serde_json::json!({
"key_id": key_pair.id,
"public_key": hex::encode(&key_pair.public_key)
})),
))
}
HsmOperation::Sign => {
let params: SignParams =
serde_json::from_value(request.parameters).map_err(|e| {
HsmError::InvalidParameters(format!("Invalid sign parameters: {}", e))
})?;
let signature = self
.sign(
¶ms.key_name,
params.algorithm.into(),
¶ms.data.as_bytes(),
)
.await?;
Ok(HsmResponse::success(
request.id,
Some(serde_json::json!({
"signature": hex::encode(&signature)
})),
))
}
HsmOperation::Verify => {
let params: VerifyParams =
serde_json::from_value(request.parameters).map_err(|e| {
HsmError::InvalidParameters(format!("Invalid verify parameters: {}", e))
})?;
let valid = self
.verify(
¶ms.key_name,
params.algorithm.into(),
¶ms.data.as_bytes(),
¶ms.signature.as_bytes(),
)
.await?;
Ok(HsmResponse::success(
request.id,
Some(serde_json::json!({
"valid": valid
})),
))
}
HsmOperation::ExportPublicKey => {
let params: GetKeyParams =
serde_json::from_value(request.parameters).map_err(|e| {
HsmError::InvalidParameters(format!("Invalid get key parameters: {}", e))
})?;
let public_key = self.export_public_key(¶ms.key_name).await?;
Ok(HsmResponse::success(
request.id,
Some(serde_json::json!({
"public_key": hex::encode(&public_key)
})),
))
}
HsmOperation::ListKeys => {
let keys = self.list_keys().await?;
Ok(HsmResponse::success(
request.id,
Some(serde_json::to_value(keys)?),
))
}
HsmOperation::DeleteKey => {
let params: DeleteKeyParams =
serde_json::from_value(request.parameters).map_err(|e| {
HsmError::InvalidParameters(format!("Invalid delete key parameters: {}", e))
})?;
self.delete_key(¶ms.key_name).await?;
Ok(HsmResponse::success(request.id, None))
}
HsmOperation::GetStatus => {
let status = self.get_status().await?;
Ok(HsmResponse::success(
request.id,
Some(serde_json::to_value(status)?),
))
}
_ => Err(HsmError::UnsupportedOperation(format!(
"Operation {:?} not supported",
request.operation
))),
}
}
}