use crate::{
algorithm::structures::SensitiveData,
constants::{
algorithm::{Cipher, HashingAlgorithm},
types::session::SessionType,
},
handles::{AuthHandle, NvIndexHandle, ObjectHandle, SessionHandle, TpmHandle},
nv::storage::{NvAuthorization, NvPublic},
session::{HmacSession, PolicySession, Session, TrialSession},
structures::{
Auth, Data, Digest, DigestList, HashcheckTicket, MaxBuffer, MaxNvBuffer, Name, Nonce,
PcrSelectionList, PublicKeyRSA,
},
tcti::Tcti,
tss2_esys::*,
utils::{
Hierarchy, PcrData, PublicParmsUnion, Signature, TpmaSession, TpmaSessionBuilder,
TpmsContext,
},
Error, Result, WrapperErrorKind as ErrorKind,
};
use log::{error, info};
use mbox::MBox;
use std::collections::HashSet;
use std::convert::{TryFrom, TryInto};
use std::ffi::CString;
use std::ptr::{null, null_mut};
use zeroize::Zeroize;
#[derive(Debug)]
pub struct Context {
esys_context: Option<MBox<ESYS_CONTEXT>>,
sessions: (ESYS_TR, ESYS_TR, ESYS_TR),
tcti_context: Option<MBox<TSS2_TCTI_CONTEXT>>,
open_handles: HashSet<ESYS_TR>,
}
impl Context {
pub unsafe fn new(tcti: Tcti) -> Result<Self> {
let mut esys_context = null_mut();
let mut tcti_context = null_mut();
let tcti_name_conf = CString::try_from(tcti)?;
let ret = Tss2_TctiLdr_Initialize(tcti_name_conf.as_ptr(), &mut tcti_context);
let ret = Error::from_tss_rc(ret);
if !ret.is_success() {
error!("Error when creating a TCTI context: {}.", ret);
return Err(ret);
}
let mut tcti_context = Some(MBox::from_raw(tcti_context));
let ret = Esys_Initialize(
&mut esys_context,
tcti_context.as_mut().unwrap().as_mut_ptr(),
null_mut(),
);
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let esys_context = Some(MBox::from_raw(esys_context));
let context = Context {
esys_context,
sessions: (ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE),
tcti_context,
open_handles: HashSet::new(),
};
Ok(context)
} else {
error!("Error when creating a new context: {}.", ret);
Err(ret)
}
}
#[allow(clippy::too_many_arguments)]
pub fn start_auth_session(
&mut self,
tpm_key: ESYS_TR,
bind: ESYS_TR,
nonce: Option<&Nonce>,
session_type: SessionType,
symmetric: Cipher,
auth_hash: HashingAlgorithm,
) -> Result<Session> {
let nonce_ptr: *const TPM2B_NONCE = match nonce {
Some(val) => &TPM2B_NONCE::try_from(val.clone())?,
None => null(),
};
let mut session_handle = ESYS_TR_NONE;
let ret = unsafe {
Esys_StartAuthSession(
self.mut_context(),
tpm_key,
bind,
self.sessions.0,
self.sessions.1,
self.sessions.2,
nonce_ptr,
session_type.into(),
&symmetric.into(),
auth_hash.into(),
&mut session_handle,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let _ = self.open_handles.insert(session_handle);
match session_type {
SessionType::Hmac => Ok(Session::Hmac(HmacSession::new(
SessionHandle::from(session_handle),
auth_hash,
))),
SessionType::Policy => Ok(Session::Policy(PolicySession::new(
SessionHandle::from(session_handle),
auth_hash,
))),
SessionType::Trial => Ok(Session::Trial(TrialSession::new(
SessionHandle::from(session_handle),
auth_hash,
))),
}
} else {
error!("Error when creating a session: {}.", ret);
Err(ret)
}
}
pub fn set_sessions(&mut self, session_handles: (ESYS_TR, ESYS_TR, ESYS_TR)) {
self.sessions = session_handles;
}
pub fn sessions(&self) -> (ESYS_TR, ESYS_TR, ESYS_TR) {
self.sessions
}
pub fn get_capabilities(
&mut self,
capability: TPM2_CAP,
property: u32,
property_count: u32,
) -> Result<(TPMS_CAPABILITY_DATA, bool)> {
let mut outcapabilitydata = null_mut();
let mut outmoredata: u8 = 0;
let ret = unsafe {
Esys_GetCapability(
self.mut_context(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
capability,
property,
property_count,
&mut outmoredata,
&mut outcapabilitydata,
)
};
let moredata = if outmoredata == 0 {
false
} else if outmoredata == 1 {
true
} else {
return Err(Error::WrapperError(ErrorKind::WrongValueFromTpm));
};
let capabilitydata = unsafe { MBox::from_raw(outcapabilitydata) };
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok((*capabilitydata, moredata))
} else {
Err(ret)
}
}
#[allow(clippy::too_many_arguments)]
pub fn create_primary_key(
&mut self,
primary_handle: ESYS_TR,
public: &TPM2B_PUBLIC,
auth_value: Option<&Auth>,
initial_data: Option<&SensitiveData>,
outside_info: Option<&Data>,
creation_pcrs: &[TPMS_PCR_SELECTION],
) -> Result<ESYS_TR> {
let sensitive_create = TPM2B_SENSITIVE_CREATE {
size: std::mem::size_of::<TPMS_SENSITIVE_CREATE>()
.try_into()
.unwrap(),
sensitive: TPMS_SENSITIVE_CREATE {
userAuth: TPM2B_AUTH::try_from(auth_value.cloned().unwrap_or_default())?,
data: TPM2B_SENSITIVE_DATA::try_from(initial_data.cloned().unwrap_or_default())?,
},
};
if creation_pcrs.len() > 16 {
return Err(Error::local_error(ErrorKind::WrongParamSize));
}
let mut creation_pcrs_buffer = [Default::default(); 16];
creation_pcrs_buffer[..creation_pcrs.len()]
.clone_from_slice(&creation_pcrs[..creation_pcrs.len()]);
let creation_pcrs = TPML_PCR_SELECTION {
count: creation_pcrs.len().try_into().unwrap(),
pcrSelections: creation_pcrs_buffer,
};
let mut outpublic = null_mut();
let mut creation_data = null_mut();
let mut creation_hash = null_mut();
let mut creation_ticket = null_mut();
let mut prim_key_handle = ESYS_TR_NONE;
let ret = unsafe {
Esys_CreatePrimary(
self.mut_context(),
primary_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&sensitive_create,
public,
&TPM2B_DATA::try_from(outside_info.cloned().unwrap_or_default())?,
&creation_pcrs,
&mut prim_key_handle,
&mut outpublic,
&mut creation_data,
&mut creation_hash,
&mut creation_ticket,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
unsafe {
let _ = MBox::from_raw(outpublic);
let _ = MBox::from_raw(creation_data);
let _ = MBox::from_raw(creation_hash);
let _ = MBox::from_raw(creation_ticket);
}
let _ = self.open_handles.insert(prim_key_handle);
Ok(prim_key_handle)
} else {
error!("Error in creating primary key: {}.", ret);
Err(ret)
}
}
#[allow(clippy::too_many_arguments)]
pub fn create_key(
&mut self,
parent_handle: ESYS_TR,
public: &TPM2B_PUBLIC,
auth_value: Option<&Auth>,
initial_data: Option<&SensitiveData>,
outside_info: Option<&Data>,
creation_pcrs: &[TPMS_PCR_SELECTION],
) -> Result<(TPM2B_PRIVATE, TPM2B_PUBLIC)> {
let sensitive_create = TPM2B_SENSITIVE_CREATE {
size: std::mem::size_of::<TPMS_SENSITIVE_CREATE>()
.try_into()
.unwrap(),
sensitive: TPMS_SENSITIVE_CREATE {
userAuth: TPM2B_AUTH::try_from(auth_value.cloned().unwrap_or_default())?,
data: TPM2B_SENSITIVE_DATA::try_from(initial_data.cloned().unwrap_or_default())?,
},
};
if creation_pcrs.len() > 16 {
return Err(Error::local_error(ErrorKind::WrongParamSize));
}
let mut creation_pcrs_buffer = [Default::default(); 16];
creation_pcrs_buffer[..creation_pcrs.len()]
.clone_from_slice(&creation_pcrs[..creation_pcrs.len()]);
let creation_pcrs = TPML_PCR_SELECTION {
count: creation_pcrs.len().try_into().unwrap(),
pcrSelections: creation_pcrs_buffer,
};
let mut outpublic = null_mut();
let mut outprivate = null_mut();
let mut creation_data = null_mut();
let mut digest = null_mut();
let mut creation = null_mut();
let ret = unsafe {
Esys_Create(
self.mut_context(),
parent_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&sensitive_create,
public,
&TPM2B_DATA::try_from(outside_info.cloned().unwrap_or_default())?,
&creation_pcrs,
&mut outprivate,
&mut outpublic,
&mut creation_data,
&mut digest,
&mut creation,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let outprivate = unsafe { MBox::from_raw(outprivate) };
let outpublic = unsafe { MBox::from_raw(outpublic) };
unsafe {
let _ = MBox::from_raw(creation_data);
let _ = MBox::from_raw(digest);
let _ = MBox::from_raw(creation);
}
Ok((*outprivate, *outpublic))
} else {
error!("Error in creating derived key: {}.", ret);
Err(ret)
}
}
pub fn unseal(&mut self, item_handle: ESYS_TR) -> Result<SensitiveData> {
let mut out_data = null_mut();
let ret = unsafe {
Esys_Unseal(
self.mut_context(),
item_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&mut out_data,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let out_data = unsafe { MBox::from_raw(out_data) };
Ok(SensitiveData::try_from(*out_data)?)
} else {
error!("Error in unsealing: {}.", ret);
Err(ret)
}
}
pub fn load(
&mut self,
parent_handle: ESYS_TR,
private: TPM2B_PRIVATE,
public: TPM2B_PUBLIC,
) -> Result<ESYS_TR> {
let mut handle = ESYS_TR_NONE;
let ret = unsafe {
Esys_Load(
self.mut_context(),
parent_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&private,
&public,
&mut handle,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let _ = self.open_handles.insert(handle);
Ok(handle)
} else {
error!("Error in loading: {}.", ret);
Err(ret)
}
}
pub fn sign(
&mut self,
key_handle: ESYS_TR,
digest: &Digest,
scheme: TPMT_SIG_SCHEME,
validation: &TPMT_TK_HASHCHECK,
) -> Result<Signature> {
let mut signature = null_mut();
let tss_digest = TPM2B_DIGEST::try_from(digest.clone())?;
let ret = unsafe {
Esys_Sign(
self.mut_context(),
key_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&tss_digest,
&scheme,
validation,
&mut signature,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let signature = unsafe { MBox::from_raw(signature) };
Ok(unsafe { Signature::try_from(*signature)? })
} else {
error!("Error in loading: {}.", ret);
Err(ret)
}
}
pub fn verify_signature(
&mut self,
key_handle: ESYS_TR,
digest: &Digest,
signature: &TPMT_SIGNATURE,
) -> Result<TPMT_TK_VERIFIED> {
let mut validation = null_mut();
let tss_digest = TPM2B_DIGEST::try_from(digest.clone())?;
let ret = unsafe {
Esys_VerifySignature(
self.mut_context(),
key_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&tss_digest,
signature,
&mut validation,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let validation = unsafe { MBox::from_raw(validation) };
Ok(*validation)
} else {
error!("Error in loading: {}.", ret);
Err(ret)
}
}
pub fn rsa_encrypt(
&mut self,
key_handle: ESYS_TR,
message: PublicKeyRSA,
in_scheme: &TPMT_RSA_DECRYPT,
label: Data,
) -> Result<PublicKeyRSA> {
let tss_message = TPM2B_PUBLIC_KEY_RSA::try_from(message)?;
let tss_label = TPM2B_DATA::try_from(label)?;
let mut out_data = null_mut();
let ret = unsafe {
Esys_RSA_Encrypt(
self.mut_context(),
key_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&tss_message,
in_scheme,
&tss_label,
&mut out_data,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let data = unsafe { PublicKeyRSA::try_from(*out_data)? };
Ok(data)
} else {
Err(ret)
}
}
pub fn rsa_decrypt(
&mut self,
key_handle: ESYS_TR,
cipher_text: PublicKeyRSA,
in_scheme: &TPMT_RSA_DECRYPT,
label: Data,
) -> Result<PublicKeyRSA> {
let tss_cipher_text = TPM2B_PUBLIC_KEY_RSA::try_from(cipher_text)?;
let tss_label = TPM2B_DATA::try_from(label)?;
let mut message = null_mut();
let ret = unsafe {
Esys_RSA_Decrypt(
self.mut_context(),
key_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&tss_cipher_text,
in_scheme,
&tss_label,
&mut message,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let data = unsafe { PublicKeyRSA::try_from(*message)? };
Ok(data)
} else {
Err(ret)
}
}
pub fn load_external(
&mut self,
private: &TPM2B_SENSITIVE,
public: &TPM2B_PUBLIC,
hierarchy: Hierarchy,
) -> Result<ESYS_TR> {
let mut key_handle = ESYS_TR_NONE;
let ret = unsafe {
Esys_LoadExternal(
self.mut_context(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
private,
public,
hierarchy.rh(),
&mut key_handle,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let _ = self.open_handles.insert(key_handle);
Ok(key_handle)
} else {
error!("Error in loading: {}.", ret);
Err(ret)
}
}
pub fn load_external_public(
&mut self,
public: &TPM2B_PUBLIC,
hierarchy: Hierarchy,
) -> Result<ESYS_TR> {
let mut key_handle = ESYS_TR_NONE;
let ret = unsafe {
Esys_LoadExternal(
self.mut_context(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
null(),
public,
hierarchy.rh(),
&mut key_handle,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let _ = self.open_handles.insert(key_handle);
Ok(key_handle)
} else {
error!("Error in loading: {}.", ret);
Err(ret)
}
}
pub fn read_public(&mut self, key_handle: ESYS_TR) -> Result<TPM2B_PUBLIC> {
let mut public = null_mut();
let mut name = null_mut();
let mut qualified_name = null_mut();
let ret = unsafe {
Esys_ReadPublic(
self.mut_context(),
key_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&mut public,
&mut name,
&mut qualified_name,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
unsafe {
let _ = MBox::from_raw(name);
let _ = MBox::from_raw(qualified_name);
}
let public = unsafe { MBox::<TPM2B_PUBLIC>::from_raw(public) };
Ok(*public)
} else {
error!("Error in loading: {}.", ret);
Err(ret)
}
}
pub fn flush_context(&mut self, handle: ESYS_TR) -> Result<()> {
let ret = unsafe { Esys_FlushContext(self.mut_context(), handle) };
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let _ = self.open_handles.remove(&handle);
Ok(())
} else {
error!("Error in flushing context: {}.", ret);
Err(ret)
}
}
pub fn context_save(&mut self, handle: ESYS_TR) -> Result<TpmsContext> {
let mut context = null_mut();
let ret = unsafe { Esys_ContextSave(self.mut_context(), handle, &mut context) };
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let context = unsafe { MBox::<TPMS_CONTEXT>::from_raw(context) };
Ok((*context).try_into()?)
} else {
error!("Error in saving context: {}.", ret);
Err(ret)
}
}
pub fn context_load(&mut self, context: TpmsContext) -> Result<ESYS_TR> {
let mut handle = ESYS_TR_NONE;
let ret = unsafe {
Esys_ContextLoad(
self.mut_context(),
&TPMS_CONTEXT::try_from(context)?,
&mut handle,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let _ = self.open_handles.insert(handle);
Ok(handle)
} else {
error!("Error in loading context: {}.", ret);
Err(ret)
}
}
pub fn pcr_read(
&mut self,
pcr_selection_list: &PcrSelectionList,
) -> Result<(u32, PcrSelectionList, PcrData)> {
let mut pcr_update_counter: u32 = 0;
let mut tss_pcr_selection_list_out_ptr = null_mut();
let mut tss_digest_ptr = null_mut();
let ret = unsafe {
Esys_PCR_Read(
self.mut_context(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&pcr_selection_list.clone().into(),
&mut pcr_update_counter,
&mut tss_pcr_selection_list_out_ptr,
&mut tss_digest_ptr,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let tss_pcr_selection_list_out =
unsafe { MBox::<TPML_PCR_SELECTION>::from_raw(tss_pcr_selection_list_out_ptr) };
let tss_digest = unsafe { MBox::<TPML_DIGEST>::from_raw(tss_digest_ptr) };
Ok((
pcr_update_counter,
PcrSelectionList::try_from(*tss_pcr_selection_list_out)?,
PcrData::new(tss_pcr_selection_list_out.as_ref(), tss_digest.as_ref())?,
))
} else {
error!("Error in creating derived key: {}.", ret);
Err(ret)
}
}
pub fn quote(
&mut self,
signing_key_handle: ESYS_TR,
qualifying_data: &Data,
signing_scheme: TPMT_SIG_SCHEME,
pcr_selection_list: PcrSelectionList,
) -> Result<(TPM2B_ATTEST, Signature)> {
let mut quoted = null_mut();
let mut signature = null_mut();
let tss_qualifying_data = TPM2B_DATA::try_from(qualifying_data.clone())?;
let ret = unsafe {
Esys_Quote(
self.mut_context(),
signing_key_handle,
self.sessions.0,
self.sessions.1,
self.sessions.2,
&tss_qualifying_data,
&signing_scheme,
&pcr_selection_list.into(),
&mut quoted,
&mut signature,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let quoted = unsafe { MBox::<TPM2B_ATTEST>::from_raw(quoted) };
let signature = unsafe { MBox::from_raw(signature) };
Ok((*quoted, unsafe { Signature::try_from(*signature)? }))
} else {
error!("Error in quoting PCR: {}", ret);
Err(ret)
}
}
pub fn policy_pcr(
&mut self,
policy_session: Session,
pcr_policy_digest: &Digest,
pcr_selection_list: PcrSelectionList,
) -> Result<()> {
let pcr_digest = TPM2B_DIGEST::try_from(pcr_policy_digest.clone())?;
let ret = unsafe {
Esys_PolicyPCR(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&pcr_digest,
&pcr_selection_list.into(),
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_or(&mut self, policy_session: Session, digest_list: DigestList) -> Result<()> {
let digest_list = TPML_DIGEST::try_from(digest_list)?;
let ret = unsafe {
Esys_PolicyOR(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&digest_list,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_locality(
&mut self,
policy_session: Session,
locality: TPMA_LOCALITY,
) -> Result<()> {
let ret = unsafe {
Esys_PolicyLocality(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
locality,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_command_code(&mut self, policy_session: Session, code: TPM2_CC) -> Result<()> {
let ret = unsafe {
Esys_PolicyCommandCode(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
code,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_physical_presence(&mut self, policy_session: Session) -> Result<()> {
let ret = unsafe {
Esys_PolicyPhysicalPresence(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_cp_hash(&mut self, policy_session: Session, cp_hash_a: &Digest) -> Result<()> {
let cp_hash_a = TPM2B_DIGEST::try_from(cp_hash_a.clone())?;
let ret = unsafe {
Esys_PolicyCpHash(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&cp_hash_a,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_name_hash(&mut self, policy_session: Session, name_hash: &Digest) -> Result<()> {
let name_hash = TPM2B_DIGEST::try_from(name_hash.clone())?;
let ret = unsafe {
Esys_PolicyNameHash(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&name_hash,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_auth_value(&mut self, policy_session: Session) -> Result<()> {
let ret = unsafe {
Esys_PolicyAuthValue(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_password(&mut self, policy_session: Session) -> Result<()> {
let ret = unsafe {
Esys_PolicyPassword(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_nv_written(&mut self, policy_session: Session, written_set: bool) -> Result<()> {
let ret = unsafe {
Esys_PolicyNvWritten(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
if written_set { 1 } else { 0 },
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn policy_authorize(
&mut self,
policy_session: Session,
approved_policy: &Digest,
policy_ref: &Nonce,
key_sign: &Name,
check_ticket: TPMT_TK_VERIFIED,
) -> Result<()> {
let tss_approved_policy = TPM2B_DIGEST::try_from(approved_policy.clone())?;
let tss_policy_ref = TPM2B_NONCE::try_from(policy_ref.clone())?;
let tss_key_sign = TPM2B_NAME::try_from(key_sign.clone())?;
let ret = unsafe {
Esys_PolicyAuthorize(
self.mut_context(),
policy_session.handle().into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&tss_approved_policy,
&tss_policy_ref,
&tss_key_sign,
&check_ticket,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn get_random(&mut self, num_bytes: usize) -> Result<Digest> {
let mut buffer = null_mut();
let ret = unsafe {
Esys_GetRandom(
self.mut_context(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
num_bytes
.try_into()
.map_err(|_| Error::local_error(ErrorKind::WrongParamSize))?,
&mut buffer,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let buffer = unsafe { MBox::from_raw(buffer) };
let mut random = buffer.buffer.to_vec();
random.truncate(buffer.size.try_into().unwrap());
Ok(Digest::try_from(random)?)
} else {
error!("Error in flushing context: {}.", ret);
Err(ret)
}
}
pub fn test_parms(&mut self, parms: PublicParmsUnion) -> Result<()> {
let public_parms = TPMT_PUBLIC_PARMS {
type_: parms.object_type(),
parameters: parms.into(),
};
let ret = unsafe {
Esys_TestParms(
self.mut_context(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&public_parms,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
error!("Error while testing parameters: {}.", ret);
Err(ret)
}
}
pub fn hash(
&mut self,
data: &MaxBuffer,
hashing_algorithm: HashingAlgorithm,
hierarchy: Hierarchy,
) -> Result<(Digest, HashcheckTicket)> {
let in_data = TPM2B_MAX_BUFFER::try_from(data.clone())?;
let mut out_hash_ptr = null_mut();
let mut validation_ptr = null_mut();
let ret = unsafe {
Esys_Hash(
self.mut_context(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&in_data,
hashing_algorithm.into(),
hierarchy.rh(),
&mut out_hash_ptr,
&mut validation_ptr,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let out_hash = unsafe { MBox::<TPM2B_DIGEST>::from_raw(out_hash_ptr) };
let validation = unsafe { MBox::<TPMT_TK_HASHCHECK>::from_raw(validation_ptr) };
Ok((
Digest::try_from(*out_hash)?,
HashcheckTicket::try_from(*validation)?,
))
} else {
error!("Error failed to peform hash operation: {}.", ret);
Err(ret)
}
}
pub fn policy_get_digest(&mut self, policy_session_handle: SessionHandle) -> Result<Digest> {
let mut policy_digest_ptr = null_mut();
let ret = unsafe {
Esys_PolicyGetDigest(
self.mut_context(),
policy_session_handle.into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&mut policy_digest_ptr,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let policy_digest = unsafe { MBox::<TPM2B_DIGEST>::from_raw(policy_digest_ptr) };
Ok(Digest::try_from(*policy_digest)?)
} else {
error!(
"Error failed to peform policy get digest operation: {}.",
ret
);
Err(ret)
}
}
pub fn tr_set_auth(&mut self, object_handle: ObjectHandle, auth: &Auth) -> Result<()> {
let mut tss_auth = TPM2B_AUTH::try_from(auth.clone())?;
let ret = unsafe { Esys_TR_SetAuth(self.mut_context(), object_handle.into(), &tss_auth) };
tss_auth.buffer.zeroize();
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn tr_get_name(&mut self, object_handle: ObjectHandle) -> Result<Name> {
let mut name = null_mut();
let ret = unsafe { Esys_TR_GetName(self.mut_context(), object_handle.into(), &mut name) };
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let tss_name = unsafe { MBox::<TPM2B_NAME>::from_raw(name) };
Ok(Name::try_from(*tss_name)?)
} else {
error!("Error in getting name: {}.", ret);
Err(ret)
}
}
pub fn tr_sess_set_attributes(
&mut self,
handle: SessionHandle,
attributes: TpmaSession,
) -> Result<()> {
let ret = unsafe {
Esys_TRSess_SetAttributes(
self.mut_context(),
handle.into(),
attributes.flags(),
attributes.mask(),
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn tr_sess_get_attributes(&mut self, object_handle: ObjectHandle) -> Result<TpmaSession> {
let mut flags: TPMA_SESSION = 0;
let ret = unsafe {
Esys_TRSess_GetAttributes(self.mut_context(), object_handle.into(), &mut flags)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(TpmaSessionBuilder::new().with_flag(flags).build())
} else {
Err(ret)
}
}
pub fn tr_from_tpm_public(&mut self, tpm_handle: TpmHandle) -> Result<ObjectHandle> {
let mut tss_esys_object_handle: ESYS_TR = ESYS_TR_NONE;
let ret = unsafe {
Esys_TR_FromTPMPublic(
self.mut_context(),
tpm_handle.into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&mut tss_esys_object_handle,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(ObjectHandle::from(tss_esys_object_handle))
} else {
Err(ret)
}
}
pub fn tr_close(&mut self, object_handle: &mut ObjectHandle) -> Result<()> {
let mut tss_esys_object_handle: ESYS_TR = (*object_handle).into();
let ret = unsafe { Esys_TR_Close(self.mut_context(), &mut tss_esys_object_handle) };
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
*object_handle = ObjectHandle::from(tss_esys_object_handle);
Ok(())
} else {
Err(ret)
}
}
pub fn nv_define_space(
&mut self,
nv_authorization: NvAuthorization,
auth: Option<&Auth>,
public_info: &NvPublic,
) -> Result<NvIndexHandle> {
let tss_auth = TPM2B_AUTH::try_from(auth.cloned().unwrap_or_default())?;
let tss_nv_public = TPM2B_NV_PUBLIC::try_from(public_info.clone())?;
let mut object_identifier: ESYS_TR = ESYS_TR_NONE;
let ret = unsafe {
Esys_NV_DefineSpace(
self.mut_context(),
nv_authorization.into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&tss_auth,
&tss_nv_public,
&mut object_identifier,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(NvIndexHandle::from(object_identifier))
} else {
Err(ret)
}
}
pub fn nv_undefine_space(
&mut self,
nv_authorization: NvAuthorization,
nv_index_handle: NvIndexHandle,
) -> Result<()> {
let ret = unsafe {
Esys_NV_UndefineSpace(
self.mut_context(),
nv_authorization.into(),
nv_index_handle.into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
pub fn nv_read_public(&mut self, nv_index_handle: NvIndexHandle) -> Result<(NvPublic, Name)> {
let mut tss_nv_public_ptr = null_mut();
let mut tss_nv_name_ptr = null_mut();
let ret = unsafe {
Esys_NV_ReadPublic(
self.mut_context(),
nv_index_handle.into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&mut tss_nv_public_ptr,
&mut tss_nv_name_ptr,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let tss_nv_public = unsafe { MBox::<TPM2B_NV_PUBLIC>::from_raw(tss_nv_public_ptr) };
let tss_nv_name = unsafe { MBox::<TPM2B_NAME>::from_raw(tss_nv_name_ptr) };
Ok((
NvPublic::try_from(*tss_nv_public)?,
Name::try_from(*tss_nv_name)?,
))
} else {
Err(ret)
}
}
pub fn nv_read(
&mut self,
auth_handle: AuthHandle,
nv_index_handle: NvIndexHandle,
size: u16,
offset: u16,
) -> Result<MaxNvBuffer> {
let mut tss_max_nv_buffer_ptr = null_mut();
let ret = unsafe {
Esys_NV_Read(
self.mut_context(),
auth_handle.into(),
nv_index_handle.into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
size,
offset,
&mut tss_max_nv_buffer_ptr,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let tss_max_nv_buffer =
unsafe { MBox::<TPM2B_MAX_NV_BUFFER>::from_raw(tss_max_nv_buffer_ptr) };
Ok(MaxNvBuffer::try_from(*tss_max_nv_buffer)?)
} else {
Err(ret)
}
}
pub fn nv_write(
&mut self,
auth_handle: AuthHandle,
nv_index_handle: NvIndexHandle,
data: &MaxNvBuffer,
offset: u16,
) -> Result<()> {
let ret = unsafe {
Esys_NV_Write(
self.mut_context(),
auth_handle.into(),
nv_index_handle.into(),
self.sessions.0,
self.sessions.1,
self.sessions.2,
&data.clone().try_into()?,
offset,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(())
} else {
Err(ret)
}
}
fn mut_context(&mut self) -> *mut ESYS_CONTEXT {
self.esys_context.as_mut().unwrap().as_mut_ptr()
}
}
impl Drop for Context {
fn drop(&mut self) {
info!("Closing context.");
self.open_handles.clone().iter().for_each(|handle| {
info!("Flushing handle {}", *handle);
if let Err(e) = self.flush_context(*handle) {
error!("Error when dropping the context: {}.", e);
}
});
let esys_context = self.esys_context.take().unwrap();
let tcti_context = self.tcti_context.take().unwrap();
unsafe { Tss2_TctiLdr_Finalize(&mut tcti_context.into_raw()) };
unsafe { Esys_Finalize(&mut esys_context.into_raw()) };
info!("Context closed.");
}
}