Skip to main content

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