use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TpmRc(u32);
impl TpmRc {
#[inline]
pub fn is_success(self) -> bool {
self.0 == 0
}
#[inline]
pub fn raw(self) -> u32 {
self.0
}
#[inline]
pub(crate) fn from_raw(rc: u32) -> Self {
TpmRc(rc)
}
}
impl fmt::Display for TpmRc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(name) = wolftpm_sys::tpm_rc::tpm_rc_name(self.0) {
write!(f, "0x{:08x} ({name})", self.0)
} else {
write!(f, "0x{:08x}", self.0)
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Error {
Tpm {
rc: TpmRc,
},
InvalidArg(&'static str),
InvalidPcrIndex(u8),
InvalidHashLen {
got: usize,
},
SignatureInvalid,
BufferTooSmall,
UnexpectedResponse,
}
impl Error {
#[inline]
pub fn check(rc: i32) -> Result<(), Error> {
if rc == 0 {
Ok(())
} else {
Err(Error::Tpm {
rc: TpmRc(rc as u32),
})
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Tpm { rc } => {
if rc.0 >= 0x8000_0000 {
write!(f, "wolfTPM internal error {rc}")
} else {
write!(f, "TPM error {rc}")
}
}
Error::InvalidArg(msg) => write!(f, "invalid argument: {msg}"),
Error::InvalidPcrIndex(n) => {
write!(f, "PCR index {n} is out of range (valid range: 0–23)")
}
Error::InvalidHashLen { got } => {
write!(f, "hash must be exactly 32 bytes, got {got}")
}
Error::SignatureInvalid => write!(f, "signature verification failed"),
Error::BufferTooSmall => write!(f, "response buffer too small"),
Error::UnexpectedResponse => write!(f, "TPM returned unexpected response"),
}
}
}
impl std::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_check_success() {
assert_eq!(Error::check(0), Ok(()));
}
#[test]
fn test_check_failure() {
assert_eq!(
Error::check(1),
Err(Error::Tpm { rc: TpmRc(1) })
);
}
#[test]
fn test_display_known() {
let e = Error::Tpm { rc: TpmRc(257) };
let s = e.to_string();
assert!(
s.contains("TPM_RC_FAILURE"),
"expected symbolic name in display, got: {s}"
);
}
#[test]
fn test_display_unknown() {
let e = Error::Tpm {
rc: TpmRc(0xdeadbeef),
};
let s = e.to_string();
assert!(
s.contains("0xdeadbeef"),
"expected hex code in display, got: {s}"
);
}
#[test]
fn test_display_structured_variants() {
let e = Error::InvalidPcrIndex(25);
assert!(
e.to_string().contains("25"),
"InvalidPcrIndex display missing index: {e}"
);
let e = Error::InvalidHashLen { got: 16 };
assert!(
e.to_string().contains("16"),
"InvalidHashLen display missing length: {e}"
);
assert!(!Error::SignatureInvalid.to_string().is_empty());
}
}