mod handle_manager;
use crate::{
attributes::SessionAttributesBuilder,
constants::{CapabilityType, PropertyTag, SessionType},
handles::{ObjectHandle, SessionHandle},
interface_types::{algorithm::HashingAlgorithm, session_handles::AuthSession},
structures::{CapabilityData, SymmetricDefinition},
tcti_ldr::{TabrmdConfig, TctiContext, TctiNameConf},
tss2_esys::*,
Error, Result, WrapperErrorKind as ErrorKind,
};
use handle_manager::HandleManager;
use log::{error, info};
use mbox::MBox;
use std::collections::HashMap;
use std::ptr::null_mut;
#[derive(Debug)]
pub struct Context {
esys_context: Option<MBox<ESYS_CONTEXT>>,
sessions: (
Option<AuthSession>,
Option<AuthSession>,
Option<AuthSession>,
),
_tcti_context: TctiContext,
handle_manager: HandleManager,
cached_tpm_properties: HashMap<PropertyTag, u32>,
}
mod tpm_commands;
mod session_administration;
mod general_esys_tr;
impl Context {
pub fn new(tcti_name_conf: TctiNameConf) -> Result<Self> {
let mut esys_context = null_mut();
let mut _tcti_context = TctiContext::initialize(tcti_name_conf)?;
let ret = unsafe {
Esys_Initialize(
&mut esys_context,
_tcti_context.tcti_context_ptr(),
null_mut(),
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let esys_context = unsafe { Some(MBox::from_raw(esys_context)) };
let context = Context {
esys_context,
sessions: (None, None, None),
_tcti_context,
handle_manager: HandleManager::new(),
cached_tpm_properties: HashMap::new(),
};
Ok(context)
} else {
error!("Error when creating a new context: {}", ret);
Err(ret)
}
}
pub fn new_with_tabrmd(tabrmd_conf: TabrmdConfig) -> Result<Self> {
Context::new(TctiNameConf::Tabrmd(tabrmd_conf))
}
pub fn set_sessions(
&mut self,
session_handles: (
Option<AuthSession>,
Option<AuthSession>,
Option<AuthSession>,
),
) {
self.sessions = session_handles;
}
pub fn clear_sessions(&mut self) {
self.sessions = (None, None, None)
}
pub fn sessions(
&self,
) -> (
Option<AuthSession>,
Option<AuthSession>,
Option<AuthSession>,
) {
self.sessions
}
pub fn execute_with_sessions<F, T>(
&mut self,
session_handles: (
Option<AuthSession>,
Option<AuthSession>,
Option<AuthSession>,
),
f: F,
) -> T
where
F: FnOnce(&mut Context) -> T,
{
let oldses = self.sessions();
self.set_sessions(session_handles);
let res = f(self);
self.set_sessions(oldses);
res
}
pub fn execute_with_session<F, T>(&mut self, session_handle: Option<AuthSession>, f: F) -> T
where
F: FnOnce(&mut Context) -> T,
{
self.execute_with_sessions((session_handle, None, None), f)
}
pub fn execute_without_session<F, T>(&mut self, f: F) -> T
where
F: FnOnce(&mut Context) -> T,
{
self.execute_with_sessions((None, None, None), f)
}
pub fn execute_with_nullauth_session<F, T, E>(&mut self, f: F) -> std::result::Result<T, E>
where
F: FnOnce(&mut Context) -> std::result::Result<T, E>,
E: From<Error>,
{
let auth_session = match self.start_auth_session(
None,
None,
None,
SessionType::Hmac,
SymmetricDefinition::AES_128_CFB,
HashingAlgorithm::Sha256,
)? {
Some(ses) => ses,
None => return Err(E::from(Error::local_error(ErrorKind::WrongValueFromTpm))),
};
let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
.with_decrypt(true)
.with_encrypt(true)
.build();
self.tr_sess_set_attributes(auth_session, session_attributes, session_attributes_mask)?;
let res = self.execute_with_session(Some(auth_session), f);
self.flush_context(SessionHandle::from(auth_session).into())?;
res
}
pub fn execute_with_temporary_object<F, T>(&mut self, object: ObjectHandle, f: F) -> Result<T>
where
F: FnOnce(&mut Context, ObjectHandle) -> Result<T>,
{
let res = f(self, object);
self.flush_context(object)?;
res
}
pub fn get_tpm_property(&mut self, property: PropertyTag) -> Result<Option<u32>> {
if let Some(&val) = self.cached_tpm_properties.get(&property) {
return Ok(Some(val));
}
let (capabs, _) = self.execute_without_session(|ctx| {
ctx.get_capability(CapabilityType::TpmProperties, property.into(), 4)
})?;
let props = match capabs {
CapabilityData::TpmProperties(props) => props,
_ => return Err(Error::WrapperError(ErrorKind::WrongValueFromTpm)),
};
for tagged_property in props {
let _ = self
.cached_tpm_properties
.insert(tagged_property.property(), tagged_property.value());
}
if let Some(val) = self.cached_tpm_properties.get(&property) {
return Ok(Some(*val));
}
Ok(None)
}
fn mut_context(&mut self) -> *mut ESYS_CONTEXT {
self.esys_context
.as_mut()
.map(MBox::<ESYS_CONTEXT>::as_mut_ptr)
.unwrap() }
fn optional_session_1(&self) -> ESYS_TR {
SessionHandle::from(self.sessions.0).into()
}
fn optional_session_2(&self) -> ESYS_TR {
SessionHandle::from(self.sessions.1).into()
}
fn optional_session_3(&self) -> ESYS_TR {
SessionHandle::from(self.sessions.2).into()
}
fn required_session_1(&self) -> Result<ESYS_TR> {
self.sessions
.0
.map(|v| SessionHandle::from(v).into())
.ok_or_else(|| {
error!("Missing session handle for authorization (authSession1 = None)");
Error::local_error(ErrorKind::MissingAuthSession)
})
}
fn required_session_2(&self) -> Result<ESYS_TR> {
self.sessions
.1
.map(|v| SessionHandle::from(v).into())
.ok_or_else(|| {
error!("Missing session handle for authorization (authSession2 = None)");
Error::local_error(ErrorKind::MissingAuthSession)
})
}
fn ffi_data_to_owned<T>(data_ptr: *mut T) -> T {
MBox::into_inner(unsafe { MBox::from_raw(data_ptr) })
}
}
impl Drop for Context {
fn drop(&mut self) {
info!("Closing context.");
for handle in self.handle_manager.handles_to_flush() {
info!("Flushing handle {}", ESYS_TR::from(handle));
if let Err(e) = self.flush_context(handle) {
error!("Error when dropping the context: {}", e);
}
}
for handle in self.handle_manager.handles_to_close().iter_mut() {
info!("Closing handle {}", ESYS_TR::from(*handle));
if let Err(e) = self.tr_close(handle) {
error!("Error when dropping context: {}.", e);
}
}
if self.handle_manager.has_open_handles() {
error!("Not all handles have had their resources successfully released");
}
unsafe {
Esys_Finalize(
&mut self
.esys_context
.take()
.map(MBox::<ESYS_CONTEXT>::into_raw)
.unwrap(), )
};
info!("Context closed.");
}
}