diff --git a/api/lib/src/ddi/mod.rs b/api/lib/src/ddi/mod.rs index 00b855e20..66d435c6a 100644 --- a/api/lib/src/ddi/mod.rs +++ b/api/lib/src/ddi/mod.rs @@ -96,6 +96,11 @@ const _: () = assert!(crate::PSK_LEN == azihsm_ddi_tbor_types::PSK_LEN); /// /// All remaining `DdiError` variants are logged and collapsed into /// `HsmError::DdiCmdFailure`. +/// +/// Every `TborStatus::Crypto*`/`CryptoCpt*` CPT (`CryptoController`) status is +/// mapped 1:1 (by variant/name) to a dedicated `HsmError` variant so callers can +/// distinguish CPT-originated failures instead of collapsing them into +/// `DdiCmdFailure`. impl From for HsmError { fn from(err: DdiError) -> Self { match err { @@ -138,6 +143,78 @@ impl From for HsmError { // `InvalidArgument` the host guards return, so callers see a // consistent argument-rejection error across transports. DdiError::TborStatus(TborStatus::InvalidArg) => HsmError::InvalidArgument, + DdiError::TborStatus(TborStatus::CryptoNotInitialized) => { + HsmError::CryptoNotInitialized + } + DdiError::TborStatus(TborStatus::CryptoBufferTooSmall) => { + HsmError::CryptoBufferTooSmall + } + DdiError::TborStatus(TborStatus::CryptoInputTooLarge) => HsmError::CryptoInputTooLarge, + DdiError::TborStatus(TborStatus::CryptoInvalidAlg) => HsmError::CryptoInvalidAlg, + DdiError::TborStatus(TborStatus::CryptoTimeout) => HsmError::CryptoTimeout, + DdiError::TborStatus(TborStatus::CryptoUnalignedCptr) => HsmError::CryptoUnalignedCptr, + DdiError::TborStatus(TborStatus::CryptoInvalidArg) => HsmError::CryptoInvalidArg, + DdiError::TborStatus(TborStatus::CryptoInvalidIvLength) => { + HsmError::CryptoInvalidIvLength + } + DdiError::TborStatus(TborStatus::CryptoInvalidKeyLength) => { + HsmError::CryptoInvalidKeyLength + } + DdiError::TborStatus(TborStatus::CryptoInvalidDataLength) => { + HsmError::CryptoInvalidDataLength + } + DdiError::TborStatus(TborStatus::CryptoInvalidContextLength) => { + HsmError::CryptoInvalidContextLength + } + DdiError::TborStatus(TborStatus::CryptoInvalidPartialContext) => { + HsmError::CryptoInvalidPartialContext + } + DdiError::TborStatus(TborStatus::CryptoUnsupportedMode) => { + HsmError::CryptoUnsupportedMode + } + DdiError::TborStatus(TborStatus::CryptoUnalignedBuffer) => { + HsmError::CryptoUnalignedBuffer + } + DdiError::TborStatus(TborStatus::CryptoNotSupported) => HsmError::CryptoNotSupported, + DdiError::TborStatus(TborStatus::CryptoHardwareError) => HsmError::CryptoHardwareError, + DdiError::TborStatus(TborStatus::CryptoCptRsaUcErrModLenInvalid) => { + HsmError::CryptoCptRsaUcErrModLenInvalid + } + DdiError::TborStatus(TborStatus::CryptoCptRsaUcErrExpLenInvalid) => { + HsmError::CryptoCptRsaUcErrExpLenInvalid + } + DdiError::TborStatus(TborStatus::CryptoCptRsaUcErrDataLenInvalid) => { + HsmError::CryptoCptRsaUcErrDataLenInvalid + } + DdiError::TborStatus(TborStatus::CryptoCptGcUcErrDataLenInvalid) => { + HsmError::CryptoCptGcUcErrDataLenInvalid + } + DdiError::TborStatus(TborStatus::CryptoCptGcUcErrCipherUnsupported) => { + HsmError::CryptoCptGcUcErrCipherUnsupported + } + DdiError::TborStatus(TborStatus::CryptoCptGcUcErrAuthUnsupported) => { + HsmError::CryptoCptGcUcErrAuthUnsupported + } + DdiError::TborStatus(TborStatus::CryptoCptGcUcErrHashModeUnsupported) => { + HsmError::CryptoCptGcUcErrHashModeUnsupported + } + DdiError::TborStatus(TborStatus::CryptoCptGcUcErrIcvMiscompare) => { + HsmError::CryptoCptGcUcErrIcvMiscompare + } + DdiError::TborStatus(TborStatus::CryptoCptGcUcErrKeyLenInvalid) => { + HsmError::CryptoCptGcUcErrKeyLenInvalid + } + DdiError::TborStatus(TborStatus::CryptoCptRsaUcErrPkcsDecoding) => { + HsmError::CryptoCptRsaUcErrPkcsDecoding + } + DdiError::TborStatus(TborStatus::CryptoCptRsaUcErrPkcsSignatureInvalid) => { + HsmError::CryptoCptRsaUcErrPkcsSignatureInvalid + } + DdiError::TborStatus(TborStatus::CryptoCptFault) => HsmError::CryptoCptFault, + DdiError::TborStatus(TborStatus::CryptoCptSwErr) => HsmError::CryptoCptSwErr, + DdiError::TborStatus(TborStatus::CryptoCptHwErr) => HsmError::CryptoCptHwErr, + DdiError::TborStatus(TborStatus::CryptoCptInstErr) => HsmError::CryptoCptInstErr, + DdiError::TborStatus(TborStatus::CryptoCptSwWarn) => HsmError::CryptoCptSwWarn, _ => { tracing::error!(?err, hsm_error = ?HsmError::DdiCmdFailure, "Unmapped DDI error"); HsmError::DdiCmdFailure @@ -291,4 +368,139 @@ mod tests { Err(HsmError::UnsupportedKeyOperation) )); } + + /// Every CPT (`CryptoController`) `TborStatus` must map 1:1 to the + /// identically-named `HsmError` variant. Guards against a missing or + /// wrong match arm silently regressing the FW-side range mirror. + #[test] + fn cpt_tbor_status_maps_to_matching_hsm_error() { + let cases = [ + // Software validation / PAL / runtime errors. + ( + TborStatus::CryptoNotInitialized, + HsmError::CryptoNotInitialized, + ), + ( + TborStatus::CryptoBufferTooSmall, + HsmError::CryptoBufferTooSmall, + ), + ( + TborStatus::CryptoInputTooLarge, + HsmError::CryptoInputTooLarge, + ), + (TborStatus::CryptoInvalidAlg, HsmError::CryptoInvalidAlg), + (TborStatus::CryptoTimeout, HsmError::CryptoTimeout), + ( + TborStatus::CryptoUnalignedCptr, + HsmError::CryptoUnalignedCptr, + ), + (TborStatus::CryptoInvalidArg, HsmError::CryptoInvalidArg), + ( + TborStatus::CryptoInvalidIvLength, + HsmError::CryptoInvalidIvLength, + ), + ( + TborStatus::CryptoInvalidKeyLength, + HsmError::CryptoInvalidKeyLength, + ), + ( + TborStatus::CryptoInvalidDataLength, + HsmError::CryptoInvalidDataLength, + ), + ( + TborStatus::CryptoInvalidContextLength, + HsmError::CryptoInvalidContextLength, + ), + ( + TborStatus::CryptoInvalidPartialContext, + HsmError::CryptoInvalidPartialContext, + ), + ( + TborStatus::CryptoUnsupportedMode, + HsmError::CryptoUnsupportedMode, + ), + ( + TborStatus::CryptoUnalignedBuffer, + HsmError::CryptoUnalignedBuffer, + ), + (TborStatus::CryptoNotSupported, HsmError::CryptoNotSupported), + ( + TborStatus::CryptoHardwareError, + HsmError::CryptoHardwareError, + ), + // CPT hardware completion codes. + ( + TborStatus::CryptoCptRsaUcErrModLenInvalid, + HsmError::CryptoCptRsaUcErrModLenInvalid, + ), + ( + TborStatus::CryptoCptRsaUcErrExpLenInvalid, + HsmError::CryptoCptRsaUcErrExpLenInvalid, + ), + ( + TborStatus::CryptoCptRsaUcErrDataLenInvalid, + HsmError::CryptoCptRsaUcErrDataLenInvalid, + ), + ( + TborStatus::CryptoCptGcUcErrDataLenInvalid, + HsmError::CryptoCptGcUcErrDataLenInvalid, + ), + ( + TborStatus::CryptoCptGcUcErrCipherUnsupported, + HsmError::CryptoCptGcUcErrCipherUnsupported, + ), + ( + TborStatus::CryptoCptGcUcErrAuthUnsupported, + HsmError::CryptoCptGcUcErrAuthUnsupported, + ), + ( + TborStatus::CryptoCptGcUcErrHashModeUnsupported, + HsmError::CryptoCptGcUcErrHashModeUnsupported, + ), + ( + TborStatus::CryptoCptGcUcErrIcvMiscompare, + HsmError::CryptoCptGcUcErrIcvMiscompare, + ), + ( + TborStatus::CryptoCptGcUcErrKeyLenInvalid, + HsmError::CryptoCptGcUcErrKeyLenInvalid, + ), + ( + TborStatus::CryptoCptRsaUcErrPkcsDecoding, + HsmError::CryptoCptRsaUcErrPkcsDecoding, + ), + ( + TborStatus::CryptoCptRsaUcErrPkcsSignatureInvalid, + HsmError::CryptoCptRsaUcErrPkcsSignatureInvalid, + ), + // CPT completion status errors. + (TborStatus::CryptoCptFault, HsmError::CryptoCptFault), + (TborStatus::CryptoCptSwErr, HsmError::CryptoCptSwErr), + (TborStatus::CryptoCptHwErr, HsmError::CryptoCptHwErr), + (TborStatus::CryptoCptInstErr, HsmError::CryptoCptInstErr), + (TborStatus::CryptoCptSwWarn, HsmError::CryptoCptSwWarn), + ]; + + for (status, expected) in cases { + assert_eq!( + HsmError::from(DdiError::TborStatus(status)), + expected, + "TborStatus {status:?} mapped to an unexpected HsmError" + ); + } + + // Contract-level `InvalidArg` is deliberately remapped to the + // host-facing `InvalidArgument`, not a `Crypto*` variant. + assert_eq!( + HsmError::from(DdiError::TborStatus(TborStatus::InvalidArg)), + HsmError::InvalidArgument + ); + + // Any status outside the mapped set collapses into the generic + // `DdiCmdFailure` fallback. + assert_eq!( + HsmError::from(DdiError::TborStatus(TborStatus::VaultNotFound)), + HsmError::DdiCmdFailure + ); + } } diff --git a/api/lib/src/error.rs b/api/lib/src/error.rs index 8e431c2d5..f86c738c4 100644 --- a/api/lib/src/error.rs +++ b/api/lib/src/error.rs @@ -68,6 +68,48 @@ pub enum HsmError { SdAlreadyInitialized = -43, SdPeerCloningNotAllowed = -44, UnsupportedKeyOperation = -45, + + // -- CPT (CryptoController) host-facing errors ---------- + // Variant set mirrors the FW/TborStatus CPT range (same names and semantics), + // but uses host-local negative i32 values (not the wire u32 status codes). + + // Software validation / PAL / runtime errors. + CryptoNotInitialized = -46, + CryptoBufferTooSmall = -47, + CryptoInputTooLarge = -48, + CryptoInvalidAlg = -49, + CryptoTimeout = -50, + CryptoUnalignedCptr = -51, + CryptoInvalidArg = -52, + CryptoInvalidIvLength = -53, + CryptoInvalidKeyLength = -54, + CryptoInvalidDataLength = -55, + CryptoInvalidContextLength = -56, + CryptoInvalidPartialContext = -57, + CryptoUnsupportedMode = -58, + CryptoUnalignedBuffer = -59, + CryptoNotSupported = -60, + CryptoHardwareError = -61, + + // CPT hardware completion codes. + CryptoCptRsaUcErrModLenInvalid = -62, + CryptoCptRsaUcErrExpLenInvalid = -63, + CryptoCptRsaUcErrDataLenInvalid = -64, + CryptoCptGcUcErrDataLenInvalid = -65, + CryptoCptGcUcErrCipherUnsupported = -66, + CryptoCptGcUcErrAuthUnsupported = -67, + CryptoCptGcUcErrHashModeUnsupported = -68, + CryptoCptGcUcErrIcvMiscompare = -69, + CryptoCptGcUcErrKeyLenInvalid = -70, + CryptoCptRsaUcErrPkcsDecoding = -71, + CryptoCptRsaUcErrPkcsSignatureInvalid = -72, + + // CPT completion status errors. + CryptoCptFault = -73, + CryptoCptSwErr = -74, + CryptoCptHwErr = -75, + CryptoCptInstErr = -76, + CryptoCptSwWarn = -77, Panic = i32::MIN, } diff --git a/ddi/tbor/types/src/status.rs b/ddi/tbor/types/src/status.rs index 7d314a018..355746390 100644 --- a/ddi/tbor/types/src/status.rs +++ b/ddi/tbor/types/src/status.rs @@ -323,6 +323,50 @@ pub enum TborStatus { /// policy does not permit peer cloning (mirror of /// `HsmError::SdPeerCloningNotAllowed`). SdPeerCloningNotAllowed = 0x0870010A, + + // -- CPT (CryptoController) errors -------------------------------- + // Mirror of `HsmError`'s CPT range, which itself mirrors tiger-collab's + // `DeviceErrorCodes::CryptoController` range + // (fw/crates/error/src/device.rs, subopcode 0x0a). Values copied + // verbatim. + + // Software validation / PAL / runtime errors. + CryptoNotInitialized = 0x090A0001, + CryptoBufferTooSmall = 0x090A0002, + CryptoInputTooLarge = 0x090A0003, + CryptoInvalidAlg = 0x090A0004, + CryptoTimeout = 0x090A0005, + CryptoUnalignedCptr = 0x090A0006, + CryptoInvalidArg = 0x090A0007, + CryptoInvalidIvLength = 0x090A0008, + CryptoInvalidKeyLength = 0x090A0009, + CryptoInvalidDataLength = 0x090A000A, + CryptoInvalidContextLength = 0x090A000B, + CryptoInvalidPartialContext = 0x090A000C, + CryptoUnsupportedMode = 0x090A000D, + CryptoUnalignedBuffer = 0x090A000E, + CryptoNotSupported = 0x090A000F, + CryptoHardwareError = 0x090A0010, + + // CPT hardware completion codes (payload16 >= 0x0100). + CryptoCptRsaUcErrModLenInvalid = 0x090A0106, + CryptoCptRsaUcErrExpLenInvalid = 0x090A0107, + CryptoCptRsaUcErrDataLenInvalid = 0x090A0108, + CryptoCptGcUcErrDataLenInvalid = 0x090A0143, + CryptoCptGcUcErrCipherUnsupported = 0x090A0146, + CryptoCptGcUcErrAuthUnsupported = 0x090A0147, + CryptoCptGcUcErrHashModeUnsupported = 0x090A0149, + CryptoCptGcUcErrIcvMiscompare = 0x090A014C, + CryptoCptGcUcErrKeyLenInvalid = 0x090A014E, + CryptoCptRsaUcErrPkcsDecoding = 0x090A0151, + CryptoCptRsaUcErrPkcsSignatureInvalid = 0x090A0152, + + // CPT completion status errors. + CryptoCptFault = 0x090A0200, + CryptoCptSwErr = 0x090A0300, + CryptoCptHwErr = 0x090A0400, + CryptoCptInstErr = 0x090A0500, + CryptoCptSwWarn = 0x090A0600, } impl core::fmt::Debug for TborStatus { diff --git a/fw/pal/traits/src/error.rs b/fw/pal/traits/src/error.rs index 01e6cc4cc..c676897be 100644 --- a/fw/pal/traits/src/error.rs +++ b/fw/pal/traits/src/error.rs @@ -465,6 +465,50 @@ pub enum HsmError { /// An exception or interrupt with no dedicated handler reached the /// `DefaultHandler`. UnexpectedException = 0x08F00003, + + // -- CPT (CryptoController) errors -------------------------------- + // Mirror of tiger-collab's `DeviceErrorCodes::CryptoController` range + // (fw/crates/error/src/device.rs, subopcode 0x0a). Values are copied + // verbatim so CPT-originated codes carry the same numeric meaning + // across both stacks. + + // Software validation / PAL / runtime errors. + CryptoNotInitialized = 0x090A0001, + CryptoBufferTooSmall = 0x090A0002, + CryptoInputTooLarge = 0x090A0003, + CryptoInvalidAlg = 0x090A0004, + CryptoTimeout = 0x090A0005, + CryptoUnalignedCptr = 0x090A0006, + CryptoInvalidArg = 0x090A0007, + CryptoInvalidIvLength = 0x090A0008, + CryptoInvalidKeyLength = 0x090A0009, + CryptoInvalidDataLength = 0x090A000A, + CryptoInvalidContextLength = 0x090A000B, + CryptoInvalidPartialContext = 0x090A000C, + CryptoUnsupportedMode = 0x090A000D, + CryptoUnalignedBuffer = 0x090A000E, + CryptoNotSupported = 0x090A000F, + CryptoHardwareError = 0x090A0010, + + // CPT hardware completion codes (payload16 >= 0x0100). + CryptoCptRsaUcErrModLenInvalid = 0x090A0106, + CryptoCptRsaUcErrExpLenInvalid = 0x090A0107, + CryptoCptRsaUcErrDataLenInvalid = 0x090A0108, + CryptoCptGcUcErrDataLenInvalid = 0x090A0143, + CryptoCptGcUcErrCipherUnsupported = 0x090A0146, + CryptoCptGcUcErrAuthUnsupported = 0x090A0147, + CryptoCptGcUcErrHashModeUnsupported = 0x090A0149, + CryptoCptGcUcErrIcvMiscompare = 0x090A014C, + CryptoCptGcUcErrKeyLenInvalid = 0x090A014E, + CryptoCptRsaUcErrPkcsDecoding = 0x090A0151, + CryptoCptRsaUcErrPkcsSignatureInvalid = 0x090A0152, + + // CPT completion status errors. + CryptoCptFault = 0x090A0200, + CryptoCptSwErr = 0x090A0300, + CryptoCptHwErr = 0x090A0400, + CryptoCptInstErr = 0x090A0500, + CryptoCptSwWarn = 0x090A0600, } impl core::fmt::Debug for HsmError { @@ -489,3 +533,81 @@ impl From for u32 { /// A specialized [`Result`] type for HSM operations. pub type HsmResult = Result; +#[cfg(test)] +mod tests { + use super::HsmError; + + #[test] + fn cpt_error_codes_match_tiger_collab_device_error_codes() { + // Values copied from tiger-collab's `DeviceErrorCodes::CryptoController` + // range (fw/crates/error/src/device.rs); pinned here since the two + // repos do not share a crate dependency. + assert_eq!(u32::from(HsmError::CryptoNotInitialized), 0x090A0001); + assert_eq!(u32::from(HsmError::CryptoBufferTooSmall), 0x090A0002); + assert_eq!(u32::from(HsmError::CryptoInputTooLarge), 0x090A0003); + assert_eq!(u32::from(HsmError::CryptoInvalidAlg), 0x090A0004); + assert_eq!(u32::from(HsmError::CryptoTimeout), 0x090A0005); + assert_eq!(u32::from(HsmError::CryptoUnalignedCptr), 0x090A0006); + assert_eq!(u32::from(HsmError::CryptoInvalidArg), 0x090A0007); + assert_eq!(u32::from(HsmError::CryptoInvalidIvLength), 0x090A0008); + assert_eq!(u32::from(HsmError::CryptoInvalidKeyLength), 0x090A0009); + assert_eq!(u32::from(HsmError::CryptoInvalidDataLength), 0x090A000A); + assert_eq!(u32::from(HsmError::CryptoInvalidContextLength), 0x090A000B); + assert_eq!(u32::from(HsmError::CryptoInvalidPartialContext), 0x090A000C); + assert_eq!(u32::from(HsmError::CryptoUnsupportedMode), 0x090A000D); + assert_eq!(u32::from(HsmError::CryptoUnalignedBuffer), 0x090A000E); + assert_eq!(u32::from(HsmError::CryptoNotSupported), 0x090A000F); + assert_eq!(u32::from(HsmError::CryptoHardwareError), 0x090A0010); + + assert_eq!( + u32::from(HsmError::CryptoCptRsaUcErrModLenInvalid), + 0x090A0106 + ); + assert_eq!( + u32::from(HsmError::CryptoCptRsaUcErrExpLenInvalid), + 0x090A0107 + ); + assert_eq!( + u32::from(HsmError::CryptoCptRsaUcErrDataLenInvalid), + 0x090A0108 + ); + assert_eq!( + u32::from(HsmError::CryptoCptGcUcErrDataLenInvalid), + 0x090A0143 + ); + assert_eq!( + u32::from(HsmError::CryptoCptGcUcErrCipherUnsupported), + 0x090A0146 + ); + assert_eq!( + u32::from(HsmError::CryptoCptGcUcErrAuthUnsupported), + 0x090A0147 + ); + assert_eq!( + u32::from(HsmError::CryptoCptGcUcErrHashModeUnsupported), + 0x090A0149 + ); + assert_eq!( + u32::from(HsmError::CryptoCptGcUcErrIcvMiscompare), + 0x090A014C + ); + assert_eq!( + u32::from(HsmError::CryptoCptGcUcErrKeyLenInvalid), + 0x090A014E + ); + assert_eq!( + u32::from(HsmError::CryptoCptRsaUcErrPkcsDecoding), + 0x090A0151 + ); + assert_eq!( + u32::from(HsmError::CryptoCptRsaUcErrPkcsSignatureInvalid), + 0x090A0152 + ); + + assert_eq!(u32::from(HsmError::CryptoCptFault), 0x090A0200); + assert_eq!(u32::from(HsmError::CryptoCptSwErr), 0x090A0300); + assert_eq!(u32::from(HsmError::CryptoCptHwErr), 0x090A0400); + assert_eq!(u32::from(HsmError::CryptoCptInstErr), 0x090A0500); + assert_eq!(u32::from(HsmError::CryptoCptSwWarn), 0x090A0600); + } +}