use std::ffi::CString;
use wolfhsm_sys::{
whAuthPermissions, wh_Client_AuthLogin, wh_Client_AuthLogout, wh_Client_AuthUserAdd,
wh_Client_AuthUserDelete, wh_Client_AuthUserGet, wh_Client_AuthUserSetCredentials,
wh_Client_AuthUserSetPermissions,
};
use crate::client::Client;
use crate::error::Error;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum AuthMethod {
None = 0, Pin = 1, Certificate = 2, }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UserId(pub(crate) u16);
impl UserId {
pub const fn new(id: u16) -> Self {
Self(id)
}
}
impl From<u16> for UserId {
fn from(v: u16) -> Self {
UserId(v)
}
}
impl From<UserId> for u16 {
fn from(u: UserId) -> Self {
u.0
}
}
#[derive(Debug, Clone, Copy)]
pub struct AuthPermissions(whAuthPermissions);
impl AuthPermissions {
pub fn none() -> Self {
Self(unsafe { core::mem::zeroed() })
}
pub fn as_raw_mut(&mut self) -> &mut whAuthPermissions {
&mut self.0
}
}
impl From<whAuthPermissions> for AuthPermissions {
fn from(raw: whAuthPermissions) -> Self {
Self(raw)
}
}
impl From<AuthPermissions> for whAuthPermissions {
fn from(p: AuthPermissions) -> Self {
p.0
}
}
impl Client {
pub fn auth_login(
&mut self,
method: AuthMethod,
username: &str,
auth_data: &[u8],
) -> Result<UserId, Error> {
let cname = CString::new(username).map_err(|_| Error::InvalidInput {
msg: "username contains an interior NUL byte",
})?;
let auth_len = u16::try_from(auth_data.len()).map_err(|_| Error::InvalidInput {
msg: "auth_data exceeds u16::MAX bytes",
})?;
let mut out_rc: i32 = 0;
let mut out_user_id: u16 = 0;
let rc = unsafe {
wh_Client_AuthLogin(
self.ctx_ptr(),
method as u32,
cname.as_ptr(),
auth_data.as_ptr() as *const core::ffi::c_void,
auth_len,
&mut out_rc,
&mut out_user_id,
)
};
Error::check(rc, "wh_Client_AuthLogin")?;
Error::check(out_rc, "wh_Client_AuthLogin(server)")?;
Ok(UserId(out_user_id))
}
pub fn auth_logout(&mut self, user_id: UserId) -> Result<(), Error> {
let mut out_rc: i32 = 0;
let rc = unsafe { wh_Client_AuthLogout(self.ctx_ptr(), user_id.0, &mut out_rc) };
Error::check(rc, "wh_Client_AuthLogout")?;
Error::check(out_rc, "wh_Client_AuthLogout(server)")?;
Ok(())
}
pub fn auth_user_add(
&mut self,
username: &str,
permissions: AuthPermissions,
method: AuthMethod,
credentials: &[u8],
) -> Result<UserId, Error> {
let cname = CString::new(username).map_err(|_| Error::InvalidInput {
msg: "username contains an interior NUL byte",
})?;
let cred_len = u16::try_from(credentials.len()).map_err(|_| Error::InvalidInput {
msg: "credentials exceed u16::MAX bytes",
})?;
let mut out_rc: i32 = 0;
let mut out_user_id: u16 = 0;
let rc = unsafe {
wh_Client_AuthUserAdd(
self.ctx_ptr(),
cname.as_ptr(),
permissions.into(),
method as u32,
credentials.as_ptr() as *const core::ffi::c_void,
cred_len,
&mut out_rc,
&mut out_user_id,
)
};
Error::check(rc, "wh_Client_AuthUserAdd")?;
Error::check(out_rc, "wh_Client_AuthUserAdd(server)")?;
Ok(UserId(out_user_id))
}
pub fn auth_user_get(
&mut self,
username: &str,
) -> Result<(UserId, AuthPermissions), Error> {
let cname = CString::new(username).map_err(|_| Error::InvalidInput {
msg: "username contains an interior NUL byte",
})?;
let mut out_rc: i32 = 0;
let mut out_user_id: u16 = 0;
let mut out_permissions = AuthPermissions::none();
let rc = unsafe {
wh_Client_AuthUserGet(
self.ctx_ptr(),
cname.as_ptr(),
&mut out_rc,
&mut out_user_id,
&mut out_permissions.0,
)
};
Error::check(rc, "wh_Client_AuthUserGet")?;
Error::check(out_rc, "wh_Client_AuthUserGet(server)")?;
Ok((UserId(out_user_id), out_permissions))
}
pub fn auth_user_delete(&mut self, user_id: UserId) -> Result<(), Error> {
let mut out_rc: i32 = 0;
let rc = unsafe { wh_Client_AuthUserDelete(self.ctx_ptr(), user_id.0, &mut out_rc) };
Error::check(rc, "wh_Client_AuthUserDelete")?;
Error::check(out_rc, "wh_Client_AuthUserDelete(server)")?;
Ok(())
}
pub fn auth_user_set_permissions(
&mut self,
user_id: UserId,
permissions: AuthPermissions,
) -> Result<(), Error> {
let mut out_rc: i32 = 0;
let rc = unsafe {
wh_Client_AuthUserSetPermissions(
self.ctx_ptr(),
user_id.0,
permissions.into(),
&mut out_rc,
)
};
Error::check(rc, "wh_Client_AuthUserSetPermissions")?;
Error::check(out_rc, "wh_Client_AuthUserSetPermissions(server)")?;
Ok(())
}
pub fn auth_user_set_credentials(
&mut self,
user_id: UserId,
method: AuthMethod,
current_credentials: &[u8],
new_credentials: &[u8],
) -> Result<(), Error> {
let cur_len =
u16::try_from(current_credentials.len()).map_err(|_| Error::InvalidInput {
msg: "current_credentials exceed u16::MAX bytes",
})?;
let new_len = u16::try_from(new_credentials.len()).map_err(|_| Error::InvalidInput {
msg: "new_credentials exceed u16::MAX bytes",
})?;
let mut out_rc: i32 = 0;
let rc = unsafe {
wh_Client_AuthUserSetCredentials(
self.ctx_ptr(),
user_id.0,
method as u32,
current_credentials.as_ptr() as *const core::ffi::c_void,
cur_len,
new_credentials.as_ptr() as *const core::ffi::c_void,
new_len,
&mut out_rc,
)
};
Error::check(rc, "wh_Client_AuthUserSetCredentials")?;
Error::check(out_rc, "wh_Client_AuthUserSetCredentials(server)")?;
Ok(())
}
}