tpm2_protocol/data/enum/
rc.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// Copyright (c) 2025 Opinsys Oy
3// Copyright (c) 2024-2025 Jarkko Sakkinen
4
5#[allow(unused_imports)]
6use crate::{tpm_enum, TpmDiscriminant, TpmError, TpmParse};
7use core::{
8    convert::TryFrom,
9    fmt::{self, Debug, Display, Formatter},
10};
11
12pub const TPM_RC_VER1: u32 = 0x0100;
13pub const TPM_RC_FMT1: u32 = 0x0080;
14pub const TPM_RC_WARN: u32 = 0x0900;
15pub const TPM_RC_P_BIT: u32 = 1 << 6;
16pub const TPM_RC_N_SHIFT: u32 = 8;
17pub const TPM_RC_FMT1_ERROR_MASK: u32 = 0x003F;
18
19const MAX_HANDLE_INDEX: u8 = 7;
20const SESSION_INDEX_OFFSET: u8 = 8;
21
22#[derive(Debug, PartialEq, Eq, Copy, Clone)]
23pub enum TpmRcIndex {
24    Parameter(u8),
25    Handle(u8),
26    Session(u8),
27}
28
29impl Display for TpmRcIndex {
30    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
31        match self {
32            Self::Parameter(i) => write!(f, "parameter[{i}]"),
33            Self::Handle(i) => write!(f, "handle[{i}]"),
34            Self::Session(i) => write!(f, "session[{i}]"),
35        }
36    }
37}
38
39tpm_enum! {
40    #[derive(Debug, PartialEq, Eq, Copy, Clone)]
41    #[allow(clippy::upper_case_acronyms)]
42    pub enum TpmRcBase(u32) {
43        (Success, 0x0000, "TPM_RC_SUCCESS"),
44        (BadTag, 0x001E, "TPM_RC_BAD_TAG"),
45        (Initialize, TPM_RC_VER1, "TPM_RC_INITIALIZE"),
46        (Failure, TPM_RC_VER1 | 0x001, "TPM_RC_FAILURE"),
47        (Sequence, TPM_RC_VER1 | 0x003, "TPM_RC_SEQUENCE"),
48        (Private, TPM_RC_VER1 | 0x00B, "TPM_RC_PRIVATE"),
49        (Hmac, TPM_RC_VER1 | 0x019, "TPM_RC_HMAC"),
50        (Disabled, TPM_RC_VER1 | 0x020, "TPM_RC_DISABLED"),
51        (Exclusive, TPM_RC_VER1 | 0x021, "TPM_RC_EXCLUSIVE"),
52        (AuthType, TPM_RC_VER1 | 0x024, "TPM_RC_AUTH_TYPE"),
53        (AuthMissing, TPM_RC_VER1 | 0x025, "TPM_RC_AUTH_MISSING"),
54        (Policy, TPM_RC_VER1 | 0x026, "TPM_RC_POLICY"),
55        (Pcr, TPM_RC_VER1 | 0x027, "TPM_RC_PCR"),
56        (PcrChanged, TPM_RC_VER1 | 0x028, "TPM_RC_PCR_CHANGED"),
57        (Upgrade, TPM_RC_VER1 | 0x02D, "TPM_RC_UPGRADE"),
58        (TooManyContexts, TPM_RC_VER1 | 0x02E, "TPM_RC_TOO_MANY_CONTEXTS"),
59        (AuthUnavailable, TPM_RC_VER1 | 0x02F, "TPM_RC_AUTH_UNAVAILABLE"),
60        (Reboot, TPM_RC_VER1 | 0x030, "TPM_RC_REBOOT"),
61        (Unbalanced, TPM_RC_VER1 | 0x031, "TPM_RC_UNBALANCED"),
62        (CommandSize, TPM_RC_VER1 | 0x042, "TPM_RC_COMMAND_SIZE"),
63        (CommandCode, TPM_RC_VER1 | 0x043, "TPM_RC_COMMAND_CODE"),
64        (AuthSize, TPM_RC_VER1 | 0x044, "TPM_RC_AUTHSIZE"),
65        (AuthContext, TPM_RC_VER1 | 0x045, "TPM_RC_AUTH_CONTEXT"),
66        (NvRange, TPM_RC_VER1 | 0x046, "TPM_RC_NV_RANGE"),
67        (NvSize, TPM_RC_VER1 | 0x047, "TPM_RC_NV_SIZE"),
68        (NvLocked, TPM_RC_VER1 | 0x048, "TPM_RC_NV_LOCKED"),
69        (NvAuthorization, TPM_RC_VER1 | 0x049, "TPM_RC_NV_AUTHORIZATION"),
70        (NvUninitialized, TPM_RC_VER1 | 0x04A, "TPM_RC_NV_UNINITIALIZED"),
71        (NvSpace, TPM_RC_VER1 | 0x04B, "TPM_RC_NV_SPACE"),
72        (NvDefined, TPM_RC_VER1 | 0x04C, "TPM_RC_NV_DEFINED"),
73        (BadContext, TPM_RC_VER1 | 0x050, "TPM_RC_BAD_CONTEXT"),
74        (CpHash, TPM_RC_VER1 | 0x051, "TPM_RC_CPHASH"),
75        (Parent, TPM_RC_VER1 | 0x052, "TPM_RC_PARENT"),
76        (NeedsTest, TPM_RC_VER1 | 0x053, "TPM_RC_NEEDS_TEST"),
77        (NoResult, TPM_RC_VER1 | 0x054, "TPM_RC_NO_RESULT"),
78        (Sensitive, TPM_RC_VER1 | 0x055, "TPM_RC_SENSITIVE"),
79        (ReadOnly, TPM_RC_VER1 | 0x056, "TPM_RC_READ_ONLY"),
80        (Asymmetric, TPM_RC_FMT1 | 0x001, "TPM_RC_ASYMMETRIC"),
81        (Attributes, TPM_RC_FMT1 | 0x002, "TPM_RC_ATTRIBUTES"),
82        (Hash, TPM_RC_FMT1 | 0x003, "TPM_RC_HASH"),
83        (Value, TPM_RC_FMT1 | 0x004, "TPM_RC_VALUE"),
84        (Hierarchy, TPM_RC_FMT1 | 0x005, "TPM_RC_HIERARCHY"),
85        (KeySize, TPM_RC_FMT1 | 0x007, "TPM_RC_KEY_SIZE"),
86        (Mgf, TPM_RC_FMT1 | 0x008, "TPM_RC_MGF"),
87        (Mode, TPM_RC_FMT1 | 0x009, "TPM_RC_MODE"),
88        (Type, TPM_RC_FMT1 | 0x00A, "TPM_RC_TYPE"),
89        (Handle, TPM_RC_FMT1 | 0x00B, "TPM_RC_HANDLE"),
90        (Kdf, TPM_RC_FMT1 | 0x00C, "TPM_RC_KDF"),
91        (Range, TPM_RC_FMT1 | 0x00D, "TPM_RC_RANGE"),
92        (AuthFail, TPM_RC_FMT1 | 0x00E, "TPM_RC_AUTH_FAIL"),
93        (Nonce, TPM_RC_FMT1 | 0x00F, "TPM_RC_NONCE"),
94        (Pp, TPM_RC_FMT1 | 0x010, "TPM_RC_PP"),
95        (Scheme, TPM_RC_FMT1 | 0x012, "TPM_RC_SCHEME"),
96        (Size, TPM_RC_FMT1 | 0x015, "TPM_RC_SIZE"),
97        (Symmetric, TPM_RC_FMT1 | 0x016, "TPM_RC_SYMMETRIC"),
98        (Tag, TPM_RC_FMT1 | 0x017, "TPM_RC_TAG"),
99        (Selector, TPM_RC_FMT1 | 0x018, "TPM_RC_SELECTOR"),
100        (Insufficient, TPM_RC_FMT1 | 0x01A, "TPM_RC_INSUFFICIENT"),
101        (Signature, TPM_RC_FMT1 | 0x01B, "TPM_RC_SIGNATURE"),
102        (Key, TPM_RC_FMT1 | 0x01C, "TPM_RC_KEY"),
103        (PolicyFail, TPM_RC_FMT1 | 0x01D, "TPM_RC_POLICY_FAIL"),
104        (Integrity, TPM_RC_FMT1 | 0x01F, "TPM_RC_INTEGRITY"),
105        (Ticket, TPM_RC_FMT1 | 0x020, "TPM_RC_TICKET"),
106        (ReservedBits, TPM_RC_FMT1 | 0x021, "TPM_RC_RESERVED_BITS"),
107        (BadAuth, TPM_RC_FMT1 | 0x022, "TPM_RC_BAD_AUTH"),
108        (Expired, TPM_RC_FMT1 | 0x023, "TPM_RC_EXPIRED"),
109        (PolicyCc, TPM_RC_FMT1 | 0x024, "TPM_RC_POLICY_CC"),
110        (Binding, TPM_RC_FMT1 | 0x025, "TPM_RC_BINDING"),
111        (Curve, TPM_RC_FMT1 | 0x026, "TPM_RC_CURVE"),
112        (EccPoint, TPM_RC_FMT1 | 0x027, "TPM_RC_ECC_POINT"),
113        (FwLimited, TPM_RC_FMT1 | 0x028, "TPM_RC_FW_LIMITED"),
114        (SvnLimited, TPM_RC_FMT1 | 0x029, "TPM_RC_SVN_LIMITED"),
115        (Channel, TPM_RC_FMT1 | 0x030, "TPM_RC_CHANNEL"),
116        (ChannelKey, TPM_RC_FMT1 | 0x031, "TPM_RC_CHANNEL_KEY"),
117        (ContextGap, TPM_RC_WARN | 0x001, "TPM_RC_CONTEXT_GAP"),
118        (ObjectMemory, TPM_RC_WARN | 0x002, "TPM_RC_OBJECT_MEMORY"),
119        (SessionMemory, TPM_RC_WARN | 0x003, "TPM_RC_SESSION_MEMORY"),
120        (Memory, TPM_RC_WARN | 0x004, "TPM_RC_MEMORY"),
121        (SessionHandles, TPM_RC_WARN | 0x005, "TPM_RC_SESSION_HANDLES"),
122        (ObjectHandles, TPM_RC_WARN | 0x006, "TPM_RC_OBJECT_HANDLES"),
123        (Locality, TPM_RC_WARN | 0x007, "TPM_RC_LOCALITY"),
124        (Yielded, TPM_RC_WARN | 0x008, "TPM_RC_YIELDED"),
125        (Canceled, TPM_RC_WARN | 0x009, "TPM_RC_CANCELED"),
126        (Testing, TPM_RC_WARN | 0x00A, "TPM_RC_TESTING"),
127        (ReferenceH0, TPM_RC_WARN | 0x010, "TPM_RC_REFERENCE_H0"),
128        (ReferenceH1, TPM_RC_WARN | 0x011, "TPM_RC_REFERENCE_H1"),
129        (ReferenceH2, TPM_RC_WARN | 0x012, "TPM_RC_REFERENCE_H2"),
130        (ReferenceH3, TPM_RC_WARN | 0x013, "TPM_RC_REFERENCE_H3"),
131        (ReferenceH4, TPM_RC_WARN | 0x014, "TPM_RC_REFERENCE_H4"),
132        (ReferenceH5, TPM_RC_WARN | 0x015, "TPM_RC_REFERENCE_H5"),
133        (ReferenceH6, TPM_RC_WARN | 0x016, "TPM_RC_REFERENCE_H6"),
134        (ReferenceS0, TPM_RC_WARN | 0x018, "TPM_RC_REFERENCE_S0"),
135        (ReferenceS1, TPM_RC_WARN | 0x019, "TPM_RC_REFERENCE_S1"),
136        (ReferenceS2, TPM_RC_WARN | 0x01A, "TPM_RC_REFERENCE_S2"),
137        (ReferenceS3, TPM_RC_WARN | 0x01B, "TPM_RC_REFERENCE_S3"),
138        (ReferenceS4, TPM_RC_WARN | 0x01C, "TPM_RC_REFERENCE_S4"),
139        (ReferenceS5, TPM_RC_WARN | 0x01D, "TPM_RC_REFERENCE_S5"),
140        (ReferenceS6, TPM_RC_WARN | 0x01E, "TPM_RC_REFERENCE_S6"),
141        (NvRate, TPM_RC_WARN | 0x020, "TPM_RC_NV_RATE"),
142        (Lockout, TPM_RC_WARN | 0x021, "TPM_RC_LOCKOUT"),
143        (Retry, TPM_RC_WARN | 0x022, "TPM_RC_RETRY"),
144        (NvUnavailable, TPM_RC_WARN | 0x023, "TPM_RC_NV_UNAVAILABLE"),
145        (NotUsed, 0xFFFF_FFFF, "TPM_RC_NOT_USED"),
146    }
147}
148
149/// A TPM 2.0 response code with a Format 1 structure.
150#[derive(Debug, PartialEq, Eq, Copy, Clone)]
151pub struct TpmRcFmt1 {
152    pub base: TpmRcBase,
153    pub index: Option<TpmRcIndex>,
154}
155
156/// A TPM 2.0 response code.
157#[derive(Debug, PartialEq, Eq, Copy, Clone)]
158pub enum TpmRc {
159    Fmt0(TpmRcBase),
160    Fmt1(TpmRcFmt1),
161    Warn(TpmRcBase),
162}
163
164impl TpmRc {
165    /// Returns the raw `u32` value of the response code.
166    #[must_use]
167    pub fn value(self) -> u32 {
168        match self {
169            Self::Fmt0(base) | Self::Warn(base) => base as u32,
170            Self::Fmt1(fmt1) => {
171                let mut value = fmt1.base as u32;
172                if let Some(index) = fmt1.index {
173                    let (is_parameter, num) = match index {
174                        TpmRcIndex::Parameter(n) => (true, n),
175                        TpmRcIndex::Handle(n) => (false, n),
176                        TpmRcIndex::Session(n) => (false, n + SESSION_INDEX_OFFSET),
177                    };
178
179                    if is_parameter {
180                        value |= TPM_RC_P_BIT;
181                    }
182                    value |= u32::from(num) << TPM_RC_N_SHIFT;
183                }
184                value
185            }
186        }
187    }
188
189    /// Returns the underlying `TpmRcBase` for any `TpmRc` variant.
190    #[must_use]
191    pub fn base(&self) -> TpmRcBase {
192        match self {
193            TpmRc::Fmt0(base) | TpmRc::Warn(base) => *base,
194            TpmRc::Fmt1(fmt1) => fmt1.base,
195        }
196    }
197}
198
199impl crate::TpmSized for TpmRc {
200    const SIZE: usize = core::mem::size_of::<u32>();
201    fn len(&self) -> usize {
202        Self::SIZE
203    }
204}
205
206impl crate::TpmBuild for TpmRc {
207    fn build(&self, writer: &mut crate::TpmWriter) -> crate::TpmResult<()> {
208        self.value().build(writer)
209    }
210}
211
212impl crate::TpmParse for TpmRc {
213    fn parse(buf: &[u8]) -> crate::TpmResult<(Self, &[u8])> {
214        let (val, remainder) = u32::parse(buf)?;
215        let rc = Self::try_from(val)?;
216        Ok((rc, remainder))
217    }
218}
219
220impl TryFrom<u32> for TpmRc {
221    type Error = TpmError;
222    fn try_from(value: u32) -> Result<Self, Self::Error> {
223        let base_code = if (value & TPM_RC_FMT1) != 0 {
224            TPM_RC_FMT1 | (value & TPM_RC_FMT1_ERROR_MASK)
225        } else {
226            value
227        };
228
229        let base = TpmRcBase::try_from(base_code).map_err(|()| {
230            TpmError::UnknownDiscriminant(
231                "TpmRcBase",
232                TpmDiscriminant::Unsigned(u64::from(base_code)),
233            )
234        })?;
235
236        if (value & TPM_RC_WARN) == TPM_RC_WARN {
237            Ok(Self::Warn(base))
238        } else if (value & TPM_RC_FMT1) != 0 {
239            let is_parameter = (value & TPM_RC_P_BIT) != 0;
240            let n = ((value >> TPM_RC_N_SHIFT) & 0b1111) as u8;
241
242            let index = match (is_parameter, n) {
243                (_, 0) => None,
244                (true, num) => Some(TpmRcIndex::Parameter(num)),
245                (false, num @ 1..=MAX_HANDLE_INDEX) => Some(TpmRcIndex::Handle(num)),
246                (false, num) => Some(TpmRcIndex::Session(num - SESSION_INDEX_OFFSET)),
247            };
248            Ok(Self::Fmt1(TpmRcFmt1 { base, index }))
249        } else {
250            Ok(Self::Fmt0(base))
251        }
252    }
253}
254
255impl From<TpmRcBase> for TpmRc {
256    fn from(base: TpmRcBase) -> Self {
257        Self::Fmt0(base)
258    }
259}
260
261impl Display for TpmRc {
262    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
263        match self {
264            Self::Fmt0(base) | Self::Warn(base) => write!(f, "{base}"),
265            Self::Fmt1(fmt1) => {
266                if let Some(index) = fmt1.index {
267                    write!(f, "[{}, {}]", fmt1.base, index)
268                } else {
269                    write!(f, "{}", fmt1.base)
270                }
271            }
272        }
273    }
274}