use crate::device::Device;
use crate::key::Key;
use crate::{sys, Result, TpmError, E_SESSION_IN_USE};
use core::ffi::c_int;
use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, Ordering};
const SESSION_SLOT: c_int = 1;
static SESSION_ACTIVE: AtomicBool = AtomicBool::new(false);
pub(crate) fn is_active() -> bool {
SESSION_ACTIVE.load(Ordering::Acquire)
}
pub struct Session<'d> {
session: sys::WOLFTPM2_SESSION,
dev: *mut sys::WOLFTPM2_DEV,
_marker: PhantomData<&'d Device>,
}
impl Device {
pub fn start_encrypted_session(&self, salt: &Key<'_>) -> Result<Session<'_>> {
if SESSION_ACTIVE
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
.is_err()
{
return Err(TpmError(E_SESSION_IN_USE));
}
let mut session: sys::WOLFTPM2_SESSION = unsafe { core::mem::zeroed() };
let rc = unsafe {
sys::wolfTPM2_StartSession(
self.ptr(),
&mut session,
salt.kptr(),
core::ptr::null_mut(),
sys::TPM_SE_T_TPM_SE_HMAC as sys::TPM_SE,
sys::TPM_ALG_ID_T_TPM_ALG_CFB as c_int,
)
};
if rc != 0 {
SESSION_ACTIVE.store(false, Ordering::Release);
return Err(TpmError(rc));
}
let attrs = (sys::TPMA_SESSION_mask_TPMA_SESSION_continueSession
| sys::TPMA_SESSION_mask_TPMA_SESSION_decrypt
| sys::TPMA_SESSION_mask_TPMA_SESSION_encrypt) as sys::TPMA_SESSION;
let rc =
unsafe { sys::wolfTPM2_SetAuthSession(self.ptr(), SESSION_SLOT, &mut session, attrs) };
if rc != 0 {
unsafe {
sys::wolfTPM2_UnloadHandle(self.ptr(), &mut session.handle);
crate::zeroize_raw(&mut session);
}
SESSION_ACTIVE.store(false, Ordering::Release);
return Err(TpmError(rc));
}
Ok(Session {
session,
dev: self.ptr(),
_marker: PhantomData,
})
}
}
impl<'d> Drop for Session<'d> {
fn drop(&mut self) {
unsafe {
sys::wolfTPM2_UnsetAuth(self.dev, SESSION_SLOT);
sys::wolfTPM2_UnloadHandle(self.dev, &mut self.session.handle);
crate::zeroize_raw(&mut self.session);
}
SESSION_ACTIVE.store(false, Ordering::Release);
}
}