use wolfhsm_sys::{wolfhsm_curve25519_make_key, wolfhsm_curve25519_shared_secret};
use crate::client::Client;
use crate::error::Error;
use crate::key::{with_key, KeyId};
pub struct Curve25519Key {
pub(crate) id: KeyId,
}
impl Curve25519Key {
pub(crate) fn generate(client: &mut Client) -> Result<Self, Error> {
let mut key_id: u16 = KeyId::ERASED.0;
let rc = unsafe { wolfhsm_curve25519_make_key(client.ctx_ptr(), &mut key_id) };
Error::check(rc, "wolfhsm_curve25519_make_key")?;
if key_id == KeyId::ERASED.0 {
return Err(Error::ProtocolError {
msg: "wolfhsm_curve25519_make_key: server returned WH_KEYID_ERASED (0)",
});
}
Ok(Curve25519Key { id: KeyId(key_id) })
}
pub fn public_key(&self, client: &mut Client) -> Result<[u8; 32], Error> {
let mut buf = [0u8; 32];
let rc = unsafe {
wolfhsm_sys::wolfhsm_curve25519_export_public(
client.ctx_ptr(),
self.id.0,
buf.as_mut_ptr(),
)
};
Error::check(rc, "wolfhsm_curve25519_export_public")?;
Ok(buf)
}
pub fn diffie_hellman(
&self,
client: &mut Client,
peer_public: &[u8; 32],
) -> Result<[u8; 32], Error> {
let mut buf = [0u8; 32];
let mut out_len: u32 = 32;
let rc = unsafe {
wolfhsm_curve25519_shared_secret(
client.ctx_ptr(),
self.id.0,
peer_public.as_ptr(),
32u32,
buf.as_mut_ptr(),
&mut out_len,
)
};
Error::check(rc, "wolfhsm_curve25519_shared_secret")?;
if out_len != 32 {
return Err(Error::ProtocolError {
msg: "wolfhsm_curve25519_shared_secret: unexpected output length",
});
}
Ok(buf)
}
}
impl Drop for Curve25519Key {
fn drop(&mut self) {
if self.id != KeyId::ERASED {
log::warn!(
"wolfhsm: Curve25519Key (id={}) dropped without eviction — \
HSM cache slot leaked. Use with_curve25519_key().",
self.id.0
);
}
}
}
impl Client {
pub fn with_curve25519_key<F, R>(&mut self, f: F) -> Result<R, Error>
where
F: FnOnce(&Curve25519Key, &mut Client) -> Result<R, Error>,
{
let key = Curve25519Key::generate(self)?;
with_key!(key, self, f)
}
}