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