use async_trait::async_trait;
use base64::Engine;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use serde_json::json;
use std::collections::HashMap;
use tokio::sync::Mutex;
use tracing::{debug, info};
use uuid::Uuid;
use bitcoin::{
bip32::{DerivationPath, Xpriv as ExtendedPrivKey, Xpub as ExtendedPubKey},
hashes::{sha256, Hash},
secp256k1::{ecdsa::Signature, Message, PublicKey as SepcPublicKey, Secp256k1, SecretKey},
Network,
};
use crate::security::hsm::config::BitcoinConfig;
use crate::security::hsm::error::HsmError;
use crate::security::hsm::provider::{
HsmOperation, HsmProvider, HsmProviderStatus, HsmRequest, HsmResponse, KeyGenParams, KeyInfo,
KeyPair, KeyType, SigningAlgorithm,
};
#[derive(Debug)]
pub struct BitcoinHsmProvider {
network: Network,
secp: Secp256k1<bitcoin::secp256k1::All>,
keys: Mutex<HashMap<String, KeyInfo>>,
status: Mutex<HsmProviderStatus>,
master_seed: [u8; 32],
master_xpriv: Mutex<Option<bitcoin::bip32::Xpriv>>,
master_xpub: Mutex<Option<bitcoin::bip32::Xpub>>,
}
impl BitcoinHsmProvider {
pub async fn new(config: &BitcoinConfig) -> Result<Self, HsmError> {
info!("Initializing Bitcoin HSM Provider");
let network = match config.network {
crate::security::hsm::config::BitcoinNetworkType::Mainnet => Network::Bitcoin,
crate::security::hsm::config::BitcoinNetworkType::Testnet => Network::Testnet,
crate::security::hsm::config::BitcoinNetworkType::Regtest => Network::Regtest,
crate::security::hsm::config::BitcoinNetworkType::Signet => Network::Signet,
};
let mut master_seed = [0u8; 32];
getrandom::fill(&mut master_seed).map_err(|e| {
HsmError::ProviderError(format!("Failed to generate random seed: {}", e))
})?;
let secp = Secp256k1::new();
let provider = Self {
network,
secp,
keys: Mutex::new(HashMap::new()),
status: Mutex::new(HsmProviderStatus::Initializing),
master_seed,
master_xpriv: Mutex::new(None),
master_xpub: Mutex::new(None),
};
Ok(provider)
}
async fn derive_key(&self, path: &str) -> Result<(SecretKey, SepcPublicKey), HsmError> {
let derivation_path = path
.parse::<DerivationPath>()
.map_err(|e| HsmError::InvalidParameters(format!("Invalid derivation path: {}", e)))?;
let master_xpriv_lock = self.master_xpriv.lock().await;
let master_xpriv = master_xpriv_lock
.as_ref()
.ok_or_else(|| HsmError::ProviderError("Master key not initialized".to_string()))?;
let derived_xpriv = master_xpriv
.derive_priv(&self.secp, &derivation_path)
.map_err(|e| HsmError::ProviderError(format!("Failed to derive private key: {}", e)))?;
let secret_key = derived_xpriv.private_key;
let secret_bytes = secret_key.secret_bytes();
let secret_key = SecretKey::from_slice(&secret_bytes)
.map_err(|e| HsmError::ProviderError(format!("Invalid secret key: {}", e)))?;
let public_key = secret_key.public_key(&self.secp);
Ok((secret_key, public_key))
}
async fn generate_bitcoin_key(&self, params: &KeyGenParams) -> Result<KeyPair, HsmError> {
let derivation_path = params
.attributes
.get("derivation_path")
.cloned()
.unwrap_or_else(|| format!("m/84'/0'/0'/0/{}", rand::random::<u32>() % 1000));
let (secret_key, public_key) = self.derive_key(&derivation_path).await?;
let key_id = params
.id
.clone()
.unwrap_or_else(|| Uuid::new_v4().to_string());
let key_info = KeyInfo {
id: key_id.clone(),
label: params.label.clone(),
key_type: params.key_type.clone(),
extractable: params.extractable,
usages: params.usages.clone(),
created_at: Utc::now(),
expires_at: params.expires_at,
attributes: {
let mut attributes = params.attributes.clone();
attributes.insert("derivation_path".to_string(), derivation_path);
attributes
},
};
let mut keys = self.keys.lock().await;
keys.insert(key_id.clone(), key_info);
let public_key_bytes = public_key.serialize().to_vec();
let key_pair = KeyPair {
id: key_id,
key_type: params.key_type.clone(),
public_key: public_key_bytes,
private_key_handle: format!("sk:{}", hex::encode(secret_key.secret_bytes())),
};
Ok(key_pair)
}
async fn sign_bitcoin(
&self,
key_id: &str,
data: &[u8],
algorithm: SigningAlgorithm,
) -> Result<Vec<u8>, HsmError> {
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(format!("Key not found: {}", key_id)))?;
let derivation_path = key_info
.attributes
.get("derivation_path")
.ok_or_else(|| HsmError::ProviderError("Derivation path not found".to_string()))?;
let (secret_key, _) = self.derive_key(derivation_path).await?;
let message = match algorithm {
SigningAlgorithm::EcdsaSha256 => {
let hash = sha256::Hash::hash(data);
Message::from_digest_slice(hash.as_ref())
.map_err(|e| HsmError::ProviderError(format!("Invalid message: {}", e)))?
}
_ => {
return Err(HsmError::InvalidParameters(format!(
"Unsupported algorithm: {:?}",
algorithm
)))
}
};
let signature = self.secp.sign_ecdsa(&message, &secret_key);
Ok(signature.serialize_der().to_vec())
}
async fn verify_bitcoin(
&self,
key_id: &str,
data: &[u8],
signature: &[u8],
algorithm: SigningAlgorithm,
) -> Result<bool, HsmError> {
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(format!("Key not found: {}", key_id)))?;
let derivation_path = key_info
.attributes
.get("derivation_path")
.ok_or_else(|| HsmError::ProviderError("Derivation path not found".to_string()))?;
let (_, public_key) = self.derive_key(derivation_path).await?;
let message = match algorithm {
SigningAlgorithm::EcdsaSha256 => {
let hash = sha256::Hash::hash(data);
Message::from_digest_slice(hash.as_ref())
.map_err(|e| HsmError::ProviderError(format!("Invalid message: {}", e)))?
}
_ => {
return Err(HsmError::InvalidParameters(format!(
"Unsupported algorithm: {:?}",
algorithm
)))
}
};
let signature = Signature::from_der(signature)
.map_err(|e| HsmError::ProviderError(format!("Invalid signature: {}", e)))?;
let result = self
.secp
.verify_ecdsa(&message, &signature, &public_key)
.is_ok();
Ok(result)
}
}
#[async_trait]
impl HsmProvider for BitcoinHsmProvider {
async fn initialize(&self) -> Result<(), HsmError> {
info!("Initializing Bitcoin HSM Provider");
let mut status = self.status.lock().await;
*status = HsmProviderStatus::Initializing;
let master_xpriv = ExtendedPrivKey::new_master(self.network, &self.master_seed)
.map_err(|e| HsmError::ProviderError(format!("Failed to create master key: {}", e)))?;
let master_xpub = ExtendedPubKey::from_priv(&self.secp, &master_xpriv);
let mut master_xpriv_lock = self.master_xpriv.lock().await;
*master_xpriv_lock = Some(master_xpriv);
drop(master_xpriv_lock);
let mut master_xpub_lock = self.master_xpub.lock().await;
*master_xpub_lock = Some(master_xpub);
drop(master_xpub_lock);
*status = HsmProviderStatus::Ready;
info!("Bitcoin HSM Provider initialized successfully");
Ok(())
}
async fn generate_key(&self, params: KeyGenParams) -> Result<(KeyPair, KeyInfo), HsmError> {
debug!("Generating key with params: {:?}", params);
let status = self.status.lock().await;
if *status != HsmProviderStatus::Ready {
return Err(HsmError::ProviderError(format!(
"Provider not ready: {:?}",
*status
)));
}
drop(status);
let key_pair = match ¶ms.key_type {
KeyType::Ec { curve }
if *curve == crate::security::hsm::provider::EcCurve::Secp256k1 =>
{
self.generate_bitcoin_key(¶ms).await?
}
_ => {
return Err(HsmError::InvalidParameters(format!(
"Unsupported key type: {:?}",
params.key_type
)))
}
};
let key_info = KeyInfo {
id: params
.id
.clone()
.unwrap_or_else(|| Uuid::new_v4().to_string()),
key_type: params.key_type.clone(),
attributes: params.attributes.clone(),
created_at: Utc::now(),
expires_at: params.expires_at,
usages: params.usages.clone(),
extractable: params.extractable,
label: params.label.clone(),
};
Ok((key_pair, key_info))
}
async fn sign(
&self,
key_id: &str,
algorithm: SigningAlgorithm,
data: &[u8],
) -> Result<Vec<u8>, HsmError> {
debug!(
"Signing data with key {}, algorithm {:?}",
key_id, algorithm
);
let status = self.status.lock().await;
if *status != HsmProviderStatus::Ready {
return Err(HsmError::ProviderError(format!(
"Provider not ready: {:?}",
*status
)));
}
drop(status);
self.sign_bitcoin(key_id, data, algorithm).await
}
async fn verify(
&self,
key_id: &str,
algorithm: SigningAlgorithm,
data: &[u8],
signature: &[u8],
) -> Result<bool, HsmError> {
debug!(
"Verifying signature with key {}, algorithm {:?}",
key_id, algorithm
);
let status = self.status.lock().await;
if *status != HsmProviderStatus::Ready {
return Err(HsmError::ProviderError(format!(
"Provider not ready: {:?}",
*status
)));
}
drop(status);
self.verify_bitcoin(key_id, data, signature, algorithm)
.await
}
async fn export_public_key(&self, key_id: &str) -> Result<Vec<u8>, HsmError> {
debug!("Exporting public key {}", key_id);
let status = self.status.lock().await;
if *status != HsmProviderStatus::Ready {
return Err(HsmError::ProviderError(format!(
"Provider not ready: {:?}",
*status
)));
}
drop(status);
let keys = self.keys.lock().await;
let key_info = keys
.get(key_id)
.ok_or_else(|| HsmError::KeyNotFound(format!("Key not found: {}", key_id)))?;
let derivation_path = key_info
.attributes
.get("derivation_path")
.ok_or_else(|| HsmError::ProviderError("Derivation path not found".to_string()))?;
let (_, public_key) = self.derive_key(derivation_path).await?;
Ok(public_key.serialize().to_vec())
}
async fn list_keys(&self) -> Result<Vec<KeyInfo>, HsmError> {
debug!("Listing keys");
let status = self.status.lock().await;
if *status != HsmProviderStatus::Ready {
return Err(HsmError::ProviderError(format!(
"Provider not ready: {:?}",
*status
)));
}
drop(status);
let keys = self.keys.lock().await;
let keys_list = keys.values().cloned().collect();
Ok(keys_list)
}
async fn delete_key(&self, key_id: &str) -> Result<(), HsmError> {
debug!("Deleting key {}", key_id);
let status = self.status.lock().await;
if *status != HsmProviderStatus::Ready {
return Err(HsmError::ProviderError(format!(
"Provider not ready: {:?}",
*status
)));
}
drop(status);
let mut keys = self.keys.lock().await;
if keys.remove(key_id).is_none() {
return Err(HsmError::KeyNotFound(format!("Key not found: {}", key_id)));
}
Ok(())
}
async fn get_status(&self) -> Result<HsmProviderStatus, HsmError> {
let status = self.status.lock().await;
Ok(status.clone())
}
async fn close(&self) -> Result<(), HsmError> {
debug!("Closing Bitcoin HSM Provider");
let mut status = self.status.lock().await;
*status = HsmProviderStatus::Unavailable;
let mut master_xpriv_lock = self.master_xpriv.lock().await;
*master_xpriv_lock = None;
drop(master_xpriv_lock);
let mut master_xpub_lock = self.master_xpub.lock().await;
*master_xpub_lock = None;
drop(master_xpub_lock);
Ok(())
}
async fn execute_operation(&self, request: HsmRequest) -> Result<HsmResponse, HsmError> {
debug!("Executing operation: {:?}", request.operation);
match request.operation {
HsmOperation::GenerateKey => {
let params: KeyGenParams = serde_json::from_value(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid parameters: {}", e))
})?;
let (key_pair, key_info) = self.generate_key(params).await?;
Ok(HsmResponse::success(
request.id,
Some(json!({
"key_pair": key_pair,
"key_info": key_info
})),
))
}
HsmOperation::Sign => {
let params = serde_json::from_value::<SignParams>(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid parameters: {}", e))
})?;
let data = base64::engine::general_purpose::STANDARD
.decode(¶ms.data)
.map_err(|e| HsmError::InvalidParameters(format!("Invalid data: {}", e)))?;
let signature = self.sign(¶ms.key_name, params.algorithm, &data).await?;
Ok(HsmResponse::success(
request.id,
Some(json!({
"signature": base64::engine::general_purpose::STANDARD.encode(signature)
})),
))
}
HsmOperation::Verify => {
let params = serde_json::from_value::<VerifyParams>(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid parameters: {}", e))
})?;
let data = base64::engine::general_purpose::STANDARD
.decode(¶ms.data)
.map_err(|e| HsmError::InvalidParameters(format!("Invalid data: {}", e)))?;
let signature = base64::engine::general_purpose::STANDARD
.decode(¶ms.signature)
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid signature: {}", e))
})?;
let valid = self
.verify(¶ms.key_name, params.algorithm, &data, &signature)
.await?;
Ok(HsmResponse::success(
request.id,
Some(json!({
"valid": valid
})),
))
}
HsmOperation::ExportPublicKey => {
let params = serde_json::from_value::<GetKeyParams>(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid parameters: {}", e))
})?;
let public_key = self.export_public_key(¶ms.key_name).await?;
Ok(HsmResponse::success(
request.id,
Some(json!({
"public_key": base64::engine::general_purpose::STANDARD.encode(public_key)
})),
))
}
HsmOperation::ListKeys => {
let keys = self.list_keys().await?;
Ok(HsmResponse::success(
request.id,
Some(json!({
"keys": keys
})),
))
}
HsmOperation::DeleteKey => {
let params = serde_json::from_value::<DeleteKeyParams>(request.parameters.clone())
.map_err(|e| {
HsmError::InvalidParameters(format!("Invalid parameters: {}", e))
})?;
self.delete_key(¶ms.key_name).await?;
Ok(HsmResponse::success(request.id, None))
}
_ => Err(HsmError::InvalidParameters(format!(
"Unsupported operation: {:?}",
request.operation
))),
}
}
}
#[derive(Serialize, Deserialize, Debug)]
struct SignParams {
pub key_name: String,
pub data: String,
pub algorithm: SigningAlgorithm,
}
#[derive(Serialize, Deserialize, Debug)]
struct VerifyParams {
pub key_name: String,
pub data: String,
pub signature: String,
pub algorithm: SigningAlgorithm,
}
#[derive(Serialize, Deserialize, Debug)]
struct GetKeyParams {
pub key_name: String,
}
#[derive(Serialize, Deserialize, Debug)]
struct DeleteKeyParams {
pub key_name: String,
}