use crate::{
attributes::NvIndexAttributes,
handles::NvIndexTpmHandle,
interface_types::algorithm::HashingAlgorithm,
structures::Digest,
tss2_esys::{TPM2B_NV_PUBLIC, TPMS_NV_PUBLIC},
Error, Result, WrapperErrorKind,
};
use log::error;
use std::convert::{TryFrom, TryInto};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct NvPublic {
nv_index: NvIndexTpmHandle,
name_algorithm: HashingAlgorithm,
attributes: NvIndexAttributes,
authorization_policy: Digest,
data_size: usize,
}
impl NvPublic {
const MAX_SIZE: usize = std::mem::size_of::<TPMS_NV_PUBLIC>();
pub fn nv_index(&self) -> NvIndexTpmHandle {
self.nv_index
}
pub fn name_algorithm(&self) -> HashingAlgorithm {
self.name_algorithm
}
pub fn attributes(&self) -> NvIndexAttributes {
self.attributes
}
pub fn authorization_policy(&self) -> &Digest {
&self.authorization_policy
}
pub fn data_size(&self) -> usize {
self.data_size
}
pub const fn builder() -> NvPublicBuilder {
NvPublicBuilder::new()
}
}
impl TryFrom<TPM2B_NV_PUBLIC> for NvPublic {
type Error = Error;
fn try_from(tss_nv_public: TPM2B_NV_PUBLIC) -> Result<NvPublic> {
if tss_nv_public.size as usize > NvPublic::MAX_SIZE {
error!("Encountered an invalid size of the TPMS_NV_PUBLIC");
return Err(Error::local_error(WrapperErrorKind::WrongParamSize));
}
Ok(NvPublic {
nv_index: tss_nv_public.nvPublic.nvIndex.try_into()?,
name_algorithm: tss_nv_public.nvPublic.nameAlg.try_into()?,
attributes: tss_nv_public.nvPublic.attributes.try_into()?,
authorization_policy: tss_nv_public.nvPublic.authPolicy.try_into()?,
data_size: tss_nv_public.nvPublic.dataSize as usize,
})
}
}
impl TryFrom<NvPublic> for TPM2B_NV_PUBLIC {
type Error = Error;
fn try_from(nv_public: NvPublic) -> Result<TPM2B_NV_PUBLIC> {
Ok(TPM2B_NV_PUBLIC {
size: 0,
nvPublic: TPMS_NV_PUBLIC {
nvIndex: nv_public.nv_index.into(),
nameAlg: nv_public.name_algorithm.into(),
attributes: nv_public.attributes.try_into()?,
authPolicy: nv_public.authorization_policy.into(),
dataSize: nv_public.data_size as u16,
},
})
}
}
#[derive(Debug, Default)]
pub struct NvPublicBuilder {
nv_index: Option<NvIndexTpmHandle>,
name_algorithm: Option<HashingAlgorithm>,
attributes: Option<NvIndexAttributes>,
authorization_policy: Option<Digest>,
data_size: Option<usize>,
}
impl NvPublicBuilder {
pub const fn new() -> Self {
NvPublicBuilder {
nv_index: None,
name_algorithm: None,
attributes: None,
authorization_policy: None,
data_size: None,
}
}
pub fn with_nv_index(mut self, nv_index: NvIndexTpmHandle) -> Self {
self.nv_index = Some(nv_index);
self
}
pub fn with_index_name_algorithm(mut self, nv_index_name_algorithm: HashingAlgorithm) -> Self {
self.name_algorithm = Some(nv_index_name_algorithm);
self
}
pub fn with_index_attributes(mut self, nv_index_attributes: NvIndexAttributes) -> Self {
self.attributes = Some(nv_index_attributes);
self
}
pub fn with_index_auth_policy(mut self, nv_index_auth_policy: Digest) -> Self {
self.authorization_policy = Some(nv_index_auth_policy);
self
}
pub fn with_data_area_size(mut self, nv_index_data_area_size: usize) -> Self {
self.data_size = Some(nv_index_data_area_size);
self
}
pub fn build(self) -> Result<NvPublic> {
Ok(NvPublic {
nv_index: self.nv_index.ok_or_else(|| {
error!("No NV index was specified");
Error::local_error(WrapperErrorKind::ParamsMissing)
})?,
name_algorithm: self.name_algorithm.ok_or_else(|| {
error!("No name algorithm was specified");
Error::local_error(WrapperErrorKind::ParamsMissing)
})?,
attributes: self.attributes.ok_or_else(|| {
error!("No attributes were specified");
Error::local_error(WrapperErrorKind::ParamsMissing)
})?,
authorization_policy: self.authorization_policy.unwrap_or_default(),
data_size: self
.data_size
.ok_or_else(|| {
error!("No data size specified");
Error::local_error(WrapperErrorKind::ParamsMissing)
})
.and_then(|v| {
if v > std::u16::MAX.into() {
error!("data area size is too large (>{})", std::u16::MAX);
return Err(Error::local_error(WrapperErrorKind::InvalidParam));
}
Ok(v)
})?,
})
}
}