use crate::{
interface_types::algorithm::SignatureSchemeAlgorithm,
structures::{EccSignature, HashAgile, RsaSignature},
traits::{Marshall, UnMarshall},
tss2_esys::{TPMT_SIGNATURE, TPMU_SIGNATURE},
Error, Result, WrapperErrorKind,
};
use log::error;
use std::convert::{TryFrom, TryInto};
use tss_esapi_sys::{Tss2_MU_TPMT_SIGNATURE_Marshal, Tss2_MU_TPMT_SIGNATURE_Unmarshal};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Signature {
RsaSsa(RsaSignature),
RsaPss(RsaSignature),
EcDsa(EccSignature),
EcDaa(EccSignature),
Sm2(EccSignature),
EcSchnorr(EccSignature),
Hmac(HashAgile),
Null,
}
impl Signature {
pub fn algorithm(&self) -> SignatureSchemeAlgorithm {
match self {
Signature::RsaSsa(_) => SignatureSchemeAlgorithm::RsaSsa,
Signature::RsaPss(_) => SignatureSchemeAlgorithm::RsaPss,
Signature::EcDsa(_) => SignatureSchemeAlgorithm::EcDsa,
Signature::EcDaa(_) => SignatureSchemeAlgorithm::EcDaa,
Signature::Sm2(_) => SignatureSchemeAlgorithm::Sm2,
Signature::EcSchnorr(_) => SignatureSchemeAlgorithm::EcSchnorr,
Signature::Hmac(_) => SignatureSchemeAlgorithm::Hmac,
Signature::Null => SignatureSchemeAlgorithm::Null,
}
}
}
impl TryFrom<Signature> for TPMT_SIGNATURE {
type Error = Error;
fn try_from(signature: Signature) -> Result<Self> {
let signature_algorithm = signature.algorithm().into();
match signature {
Signature::RsaSsa(rsa_signature) => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: TPMU_SIGNATURE {
rsassa: rsa_signature.into(),
},
}),
Signature::RsaPss(rsa_signature) => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: TPMU_SIGNATURE {
rsapss: rsa_signature.into(),
},
}),
Signature::EcDsa(ecc_signature) => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: TPMU_SIGNATURE {
ecdsa: ecc_signature.into(),
},
}),
Signature::EcDaa(ecc_signature) => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: TPMU_SIGNATURE {
ecdaa: ecc_signature.into(),
},
}),
Signature::Sm2(ecc_signature) => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: TPMU_SIGNATURE {
sm2: ecc_signature.into(),
},
}),
Signature::EcSchnorr(ecc_signature) => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: TPMU_SIGNATURE {
ecschnorr: ecc_signature.into(),
},
}),
Signature::Hmac(hash_agile) => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: TPMU_SIGNATURE {
hmac: hash_agile.try_into()?,
},
}),
Signature::Null => Ok(TPMT_SIGNATURE {
sigAlg: signature_algorithm,
signature: Default::default(),
}),
}
}
}
impl TryFrom<TPMT_SIGNATURE> for Signature {
type Error = Error;
fn try_from(tpmt_signature: TPMT_SIGNATURE) -> Result<Self> {
match SignatureSchemeAlgorithm::try_from(tpmt_signature.sigAlg)? {
SignatureSchemeAlgorithm::RsaSsa => Ok(Signature::RsaSsa(
unsafe { tpmt_signature.signature.rsassa }.try_into()?,
)),
SignatureSchemeAlgorithm::RsaPss => Ok(Signature::RsaPss(
unsafe { tpmt_signature.signature.rsapss }.try_into()?,
)),
SignatureSchemeAlgorithm::EcDsa => Ok(Signature::EcDsa(
unsafe { tpmt_signature.signature.ecdsa }.try_into()?,
)),
SignatureSchemeAlgorithm::EcDaa => Ok(Signature::EcDaa(
unsafe { tpmt_signature.signature.ecdaa }.try_into()?,
)),
SignatureSchemeAlgorithm::Sm2 => Ok(Signature::Sm2(
unsafe { tpmt_signature.signature.sm2 }.try_into()?,
)),
SignatureSchemeAlgorithm::EcSchnorr => Ok(Signature::EcSchnorr(
unsafe { tpmt_signature.signature.ecschnorr }.try_into()?,
)),
SignatureSchemeAlgorithm::Hmac => Ok(Signature::Hmac(
unsafe { tpmt_signature.signature.hmac }.try_into()?,
)),
SignatureSchemeAlgorithm::Null => Ok(Signature::Null),
}
}
}
impl Marshall for Signature {
const BUFFER_SIZE: usize = std::mem::size_of::<TPMT_SIGNATURE>();
fn marshall(&self) -> Result<Vec<u8>> {
let tpmt_sig = TPMT_SIGNATURE::try_from(self.clone())?;
let mut offset = 0;
let mut buffer = vec![0; Self::BUFFER_SIZE];
let ret = unsafe {
Tss2_MU_TPMT_SIGNATURE_Marshal(
&tpmt_sig,
buffer.as_mut_ptr(),
buffer.capacity().try_into().map_err(|e| {
error!("Failed to convert size of buffer to TSS size_t type: {}", e);
Error::local_error(WrapperErrorKind::InvalidParam)
})?,
&mut offset,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
let checked_offset = usize::try_from(offset).map_err(|e| {
error!("Failed to parse offset as usize: {}", e);
Error::local_error(WrapperErrorKind::InvalidParam)
})?;
buffer.truncate(checked_offset);
Ok(buffer)
} else {
Err(ret)
}
}
}
impl UnMarshall for Signature {
fn unmarshall(public_buffer: &[u8]) -> Result<Self> {
let mut tpmt_sig = TPMT_SIGNATURE::default();
let mut offset = 0;
let ret = unsafe {
Tss2_MU_TPMT_SIGNATURE_Unmarshal(
public_buffer.as_ptr(),
public_buffer.len().try_into().map_err(|e| {
error!("Failed to convert length of marshalled data: {}", e);
Error::local_error(WrapperErrorKind::InvalidParam)
})?,
&mut offset,
&mut tpmt_sig,
)
};
let ret = Error::from_tss_rc(ret);
if ret.is_success() {
Ok(tpmt_sig.try_into()?)
} else {
Err(ret)
}
}
}