use crate::error::WSError;
use crate::platform::{KeyHandle, SecureKeyProvider, SecurityLevel};
use std::sync::Arc;
use wasmtime::component::{Component, Linker, ResourceTable};
use wasmtime::{Config, Engine, Store};
wasmtime::component::bindgen!({
path: "../../wit/deps/wsc-crypto",
world: "crypto-guest",
require_store_data_send: true,
});
pub struct CryptoHostState<P: SecureKeyProvider> {
provider: Arc<P>,
pub table: ResourceTable,
}
impl<P: SecureKeyProvider> CryptoHostState<P> {
pub fn new(provider: P) -> Self {
Self {
provider: Arc::new(provider),
table: ResourceTable::new(),
}
}
pub fn provider(&self) -> &P {
&self.provider
}
}
fn to_wit_security_level(level: SecurityLevel) -> wsc::crypto::hardware_signing::SecurityLevel {
match level {
SecurityLevel::Software => wsc::crypto::hardware_signing::SecurityLevel::Software,
SecurityLevel::HardwareBasic => wsc::crypto::hardware_signing::SecurityLevel::HardwareBasic,
SecurityLevel::HardwareBacked => wsc::crypto::hardware_signing::SecurityLevel::HardwareBacked,
SecurityLevel::HardwareCertified => wsc::crypto::hardware_signing::SecurityLevel::HardwareCertified,
}
}
impl<P: SecureKeyProvider + 'static> wsc::crypto::hardware_signing::Host for CryptoHostState<P> {
fn is_available(&mut self) -> bool {
self.provider.health_check().is_ok()
}
fn get_backend_info(&mut self) -> Result<wsc::crypto::hardware_signing::BackendInfo, wsc::crypto::hardware_signing::HardwareError> {
Ok(wsc::crypto::hardware_signing::BackendInfo {
name: self.provider.name().to_string(),
level: to_wit_security_level(self.provider.security_level()),
algorithms: vec![wsc::crypto::hardware_signing::SigningAlgorithm::Ed25519],
manufacturer: None,
firmware_version: None,
})
}
fn get_security_level(&mut self) -> wsc::crypto::hardware_signing::SecurityLevel {
to_wit_security_level(self.provider.security_level())
}
fn generate_key(
&mut self,
algorithm: wsc::crypto::hardware_signing::SigningAlgorithm,
_usage: u8,
_key_id: Option<String>,
) -> Result<u64, wsc::crypto::hardware_signing::HardwareError> {
if algorithm != wsc::crypto::hardware_signing::SigningAlgorithm::Ed25519 {
return Err(wsc::crypto::hardware_signing::HardwareError::UnsupportedAlgorithm(
format!("Only Ed25519 is currently supported, got {:?}", algorithm)
));
}
self.provider
.generate_key()
.map(|h| h.as_raw())
.map_err(|e| wsc::crypto::hardware_signing::HardwareError::GenerationFailed(e.to_string()))
}
fn sign(
&mut self,
handle: u64,
data: Vec<u8>,
) -> Result<Vec<u8>, wsc::crypto::hardware_signing::HardwareError> {
let key_handle = KeyHandle::from_raw(handle);
self.provider
.sign(key_handle, &data)
.map_err(|e| wsc::crypto::hardware_signing::HardwareError::SigningFailed(e.to_string()))
}
fn get_public_key(
&mut self,
handle: u64,
) -> Result<wsc::crypto::hardware_signing::PublicKeyInfo, wsc::crypto::hardware_signing::HardwareError> {
let key_handle = KeyHandle::from_raw(handle);
let public_key = self.provider
.get_public_key(key_handle)
.map_err(|e| wsc::crypto::hardware_signing::HardwareError::KeyNotFound(e.to_string()))?;
let public_key_der = public_key.pk.as_ref().to_vec();
Ok(wsc::crypto::hardware_signing::PublicKeyInfo {
handle,
algorithm: wsc::crypto::hardware_signing::SigningAlgorithm::Ed25519,
public_key_der,
key_id: public_key.key_id.and_then(|bytes| String::from_utf8(bytes).ok()),
})
}
fn verify(
&mut self,
public_key_der: Vec<u8>,
algorithm: wsc::crypto::hardware_signing::SigningAlgorithm,
data: Vec<u8>,
signature: Vec<u8>,
) -> Result<bool, wsc::crypto::hardware_signing::HardwareError> {
if algorithm != wsc::crypto::hardware_signing::SigningAlgorithm::Ed25519 {
return Err(wsc::crypto::hardware_signing::HardwareError::UnsupportedAlgorithm(
format!("Only Ed25519 is currently supported, got {:?}", algorithm)
));
}
let pk = ed25519_compact::PublicKey::from_slice(&public_key_der)
.map_err(|e| wsc::crypto::hardware_signing::HardwareError::InvalidHandle(
format!("Invalid public key: {}", e)
))?;
let sig = ed25519_compact::Signature::from_slice(&signature)
.map_err(|e| wsc::crypto::hardware_signing::HardwareError::InvalidHandle(
format!("Invalid signature: {}", e)
))?;
Ok(pk.verify(&data, &sig).is_ok())
}
fn delete_key(&mut self, handle: u64) -> Result<(), wsc::crypto::hardware_signing::HardwareError> {
let key_handle = KeyHandle::from_raw(handle);
self.provider
.delete_key(key_handle)
.map_err(|e| wsc::crypto::hardware_signing::HardwareError::KeyNotFound(e.to_string()))
}
fn list_keys(&mut self) -> Result<Vec<u64>, wsc::crypto::hardware_signing::HardwareError> {
self.provider
.list_keys()
.map(|handles| handles.into_iter().map(|h| h.as_raw()).collect())
.map_err(|e| wsc::crypto::hardware_signing::HardwareError::NotAvailable(e.to_string()))
}
}
pub struct WscRuntime<P: SecureKeyProvider + 'static> {
engine: Engine,
linker: Linker<CryptoHostState<P>>,
}
impl<P: SecureKeyProvider + Send + Sync + 'static> WscRuntime<P> {
pub fn new() -> Result<Self, WSError> {
let mut config = Config::new();
config.wasm_component_model(true);
let engine = Engine::new(&config)
.map_err(|e| WSError::InternalError(format!("Failed to create wasmtime engine: {}", e)))?;
let mut linker = Linker::new(&engine);
CryptoGuest::add_to_linker::<CryptoHostState<P>, wasmtime::component::HasSelf<CryptoHostState<P>>>(
&mut linker,
|state| state,
)
.map_err(|e| WSError::InternalError(format!("Failed to add crypto bindings: {}", e)))?;
Ok(Self { engine, linker })
}
pub fn engine(&self) -> &Engine {
&self.engine
}
pub fn load_component(&self, bytes: &[u8]) -> Result<Component, WSError> {
Component::from_binary(&self.engine, bytes)
.map_err(|e| WSError::InternalError(format!("Failed to load component: {}", e)))
}
pub fn create_store(&self, provider: P) -> Store<CryptoHostState<P>> {
Store::new(&self.engine, CryptoHostState::new(provider))
}
pub fn instantiate(
&self,
store: &mut Store<CryptoHostState<P>>,
component: &Component,
) -> Result<CryptoGuest, WSError> {
CryptoGuest::instantiate(store, component, &self.linker)
.map_err(|e| WSError::InternalError(format!("Failed to instantiate component: {}", e)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::platform::software::SoftwareProvider;
#[test]
fn test_crypto_host_state_creation() {
let provider = SoftwareProvider::new();
let state = CryptoHostState::new(provider);
assert_eq!(state.provider().name(), "Software (Development Only)");
}
#[test]
fn test_runtime_creation() {
let runtime: WscRuntime<SoftwareProvider> = WscRuntime::new().unwrap();
let _ = runtime.engine();
}
#[test]
fn test_host_trait_implementation() {
let provider = SoftwareProvider::new();
let mut state = CryptoHostState::new(provider);
assert!(wsc::crypto::hardware_signing::Host::is_available(&mut state));
let level = wsc::crypto::hardware_signing::Host::get_security_level(&mut state);
assert_eq!(level, wsc::crypto::hardware_signing::SecurityLevel::Software);
let handle = wsc::crypto::hardware_signing::Host::generate_key(
&mut state,
wsc::crypto::hardware_signing::SigningAlgorithm::Ed25519,
0x01, Some("test-key".to_string()),
).unwrap();
assert!(handle > 0);
let data = b"test data to sign".to_vec();
let signature = wsc::crypto::hardware_signing::Host::sign(&mut state, handle, data.clone()).unwrap();
assert_eq!(signature.len(), 64);
let pk_info = wsc::crypto::hardware_signing::Host::get_public_key(&mut state, handle).unwrap();
assert_eq!(pk_info.handle, handle);
assert_eq!(pk_info.public_key_der.len(), 32);
let verified = wsc::crypto::hardware_signing::Host::verify(
&mut state,
pk_info.public_key_der,
wsc::crypto::hardware_signing::SigningAlgorithm::Ed25519,
data,
signature,
).unwrap();
assert!(verified);
let keys = wsc::crypto::hardware_signing::Host::list_keys(&mut state).unwrap();
assert!(keys.contains(&handle));
wsc::crypto::hardware_signing::Host::delete_key(&mut state, handle).unwrap();
let keys = wsc::crypto::hardware_signing::Host::list_keys(&mut state).unwrap();
assert!(!keys.contains(&handle));
}
}