1use anyhow::{Result, anyhow};
6use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
7use serde::{Deserialize, Serialize};
8use serde_annotate::Annotate;
9use std::cmp::Ordering;
10use std::io::{Read, Write};
11
12use crate::crypto::Error;
13use crate::crypto::ecdsa::EcdsaRawPublicKey;
14use crate::crypto::rsa::RsaRawPublicKey;
15use crate::crypto::spx::SpxRawPublicKey;
16use crate::util::serde::string_or_struct;
17use crate::with_unknown;
18
19with_unknown! {
20 pub enum TlvTag: u32 [default = Self::Unknown] {
21 Unknown = 0,
22 Owner = u32::from_le_bytes(*b"OWNR"),
23 ApplicationKey = u32::from_le_bytes(*b"APPK"),
24 FlashConfig = u32::from_le_bytes(*b"FLSH"),
25 FlashInfoConfig = u32::from_le_bytes(*b"INFO"),
26 Rescue = u32::from_le_bytes(*b"RESQ"),
27 DetachedSignature = u32::from_le_bytes(*b"SIGN"),
28 IntegratorSpecificFirmwareBinding = u32::from_le_bytes(*b"ISFB"),
29 NotPresent = u32::from_le_bytes(*b"ZZZZ"),
30 }
31
32 pub enum OwnershipKeyAlg: u32 [default = Self::Unknown] {
33 Unknown = 0,
34 Rsa = u32::from_le_bytes(*b"RSA3"),
35 EcdsaP256 = u32::from_le_bytes(*b"P256"),
36 SpxPure = u32::from_le_bytes(*b"S+Pu"),
37 SpxPrehash = u32::from_le_bytes(*b"S+S2"),
38 HybridSpxPure = u32::from_le_bytes(*b"H+Pu"),
39 HybridSpxPrehash = u32::from_le_bytes(*b"H+S2"),
40 }
41 pub enum DetachedSignatureCommand: u32 [default = Self::Unknown] {
42 Unknown = 0,
43 Owner = u32::from_le_bytes(*b"OWNR"),
44 Unlock = u32::from_le_bytes(*b"UNLK"),
45 Activate = u32::from_le_bytes(*b"ACTV"),
46 }
47}
48
49impl OwnershipKeyAlg {
50 pub fn is_detached(self) -> bool {
51 !matches!(self, Self::EcdsaP256)
52 }
53
54 pub fn is_ecdsa(self) -> bool {
55 matches!(
56 self,
57 Self::EcdsaP256 | Self::HybridSpxPure | Self::HybridSpxPrehash
58 )
59 }
60
61 pub fn is_spx(self) -> bool {
62 matches!(
63 self,
64 Self::SpxPure | Self::SpxPrehash | Self::HybridSpxPure | Self::HybridSpxPrehash
65 )
66 }
67
68 pub fn is_hybrid(self) -> bool {
69 matches!(self, Self::HybridSpxPure | Self::HybridSpxPrehash)
70 }
71
72 pub fn is_prehashed(self) -> bool {
73 matches!(self, Self::SpxPrehash | Self::HybridSpxPrehash)
74 }
75}
76
77#[derive(Clone, Debug, Default, Deserialize, Serialize)]
78#[serde(try_from = "String", into = "String")]
79pub struct StructVersion {
80 pub major: u8,
81 pub minor: u8,
82}
83
84impl TryFrom<&str> for StructVersion {
85 type Error = anyhow::Error;
86
87 fn try_from(s: &str) -> Result<Self, Self::Error> {
88 if let Some((major, minor)) = s.split_once('.') {
89 Ok(StructVersion {
90 major: major.parse()?,
91 minor: minor.parse()?,
92 })
93 } else {
94 Ok(StructVersion {
95 major: s.parse()?,
96 minor: 0,
97 })
98 }
99 }
100}
101
102impl TryFrom<String> for StructVersion {
103 type Error = anyhow::Error;
104 fn try_from(s: String) -> Result<Self, Self::Error> {
105 StructVersion::try_from(s.as_str())
106 }
107}
108
109impl From<StructVersion> for String {
110 fn from(sv: StructVersion) -> String {
111 format!("{}.{}", sv.major, sv.minor)
112 }
113}
114
115impl StructVersion {
116 pub fn read(src: &mut impl Read) -> Result<Self> {
117 Ok(Self {
118 major: src.read_u8()?,
119 minor: src.read_u8()?,
120 })
121 }
122 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
123 dest.write_u8(self.major)?;
124 dest.write_u8(self.minor)?;
125 Ok(())
126 }
127}
128
129#[derive(Debug, Default, Deserialize, Annotate)]
130pub struct TlvHeader {
131 #[serde(default)]
132 pub identifier: TlvTag,
133 #[serde(default)]
134 pub length: usize,
135 #[serde(default)]
136 pub version: StructVersion,
137}
138
139impl TlvHeader {
140 pub const SIZE: usize = 8;
141 pub fn new(id: TlvTag, len: usize, version: &str) -> Self {
142 Self {
143 identifier: id,
144 length: len,
145 version: version.try_into().expect("major.minor version string"),
146 }
147 }
148
149 pub fn read(src: &mut impl Read) -> Result<Self> {
150 Ok(Self {
151 identifier: TlvTag(src.read_u32::<LittleEndian>()?),
152 length: src.read_u16::<LittleEndian>()? as usize,
153 version: StructVersion::read(src)?,
154 })
155 }
156
157 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
158 dest.write_u32::<LittleEndian>(u32::from(self.identifier))?;
159 dest.write_u16::<LittleEndian>(self.length as u16)?;
160 self.version.write(dest)?;
161 Ok(())
162 }
163 pub fn write_len(&self, dest: &mut impl Write, length: usize) -> Result<()> {
164 dest.write_u32::<LittleEndian>(u32::from(self.identifier))?;
165 dest.write_u16::<LittleEndian>(length as u16)?;
166 self.version.write(dest)?;
167 Ok(())
168 }
169}
170
171#[derive(Debug, Serialize, Deserialize)]
172pub struct HybridRawPublicKey {
173 #[serde(deserialize_with = "string_or_struct")]
174 pub ecdsa: EcdsaRawPublicKey,
175 #[serde(deserialize_with = "string_or_struct")]
176 pub spx: SpxRawPublicKey,
177}
178
179impl HybridRawPublicKey {
180 const SIZE: usize = EcdsaRawPublicKey::SIZE + SpxRawPublicKey::SIZE;
181
182 pub fn read(src: &mut impl Read) -> Result<Self> {
183 Ok(Self {
184 ecdsa: EcdsaRawPublicKey::read(src)?,
185 spx: SpxRawPublicKey::read(src)?,
186 })
187 }
188
189 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
190 self.ecdsa.write(dest)?;
191 self.spx.write(dest)?;
192 Ok(())
193 }
194}
195
196#[derive(Debug, Serialize, Deserialize)]
198#[allow(clippy::len_without_is_empty)]
199pub enum KeyMaterial {
200 #[serde(alias = "unknown")]
201 Unknown(Vec<u8>),
202 #[serde(alias = "ecdsa")]
203 Ecdsa(#[serde(deserialize_with = "string_or_struct")] EcdsaRawPublicKey),
204 #[serde(alias = "rsa")]
205 Rsa(#[serde(deserialize_with = "string_or_struct")] RsaRawPublicKey),
206 #[serde(alias = "spx")]
207 Spx(#[serde(deserialize_with = "string_or_struct")] SpxRawPublicKey),
208 #[serde(alias = "hybrid")]
209 Hybrid(HybridRawPublicKey),
210}
211
212impl Default for KeyMaterial {
213 fn default() -> Self {
214 Self::Unknown(Vec::default())
215 }
216}
217
218impl KeyMaterial {
219 pub fn len(&self) -> usize {
220 match self {
221 KeyMaterial::Ecdsa(_) => EcdsaRawPublicKey::SIZE,
222 KeyMaterial::Rsa(_) => RsaRawPublicKey::SIZE,
223 KeyMaterial::Spx(_) => SpxRawPublicKey::SIZE,
224 KeyMaterial::Hybrid(_) => HybridRawPublicKey::SIZE,
225 KeyMaterial::Unknown(u) => u.len(),
226 }
227 }
228
229 pub fn kind(&self) -> OwnershipKeyAlg {
230 match self {
231 KeyMaterial::Ecdsa(_) => OwnershipKeyAlg::EcdsaP256,
232 KeyMaterial::Rsa(_) => OwnershipKeyAlg::Rsa,
233 KeyMaterial::Spx(_) => OwnershipKeyAlg::SpxPure,
234 KeyMaterial::Hybrid(_) => OwnershipKeyAlg::HybridSpxPure,
235 KeyMaterial::Unknown(_) => OwnershipKeyAlg::Unknown,
236 }
237 }
238
239 pub fn read_length(src: &mut impl Read, kind: OwnershipKeyAlg, buflen: usize) -> Result<Self> {
240 let result = match kind {
241 OwnershipKeyAlg::Rsa => KeyMaterial::Rsa(RsaRawPublicKey::read(src)?),
242 OwnershipKeyAlg::EcdsaP256 => KeyMaterial::Ecdsa(EcdsaRawPublicKey::read(src)?),
243 OwnershipKeyAlg::SpxPure | OwnershipKeyAlg::SpxPrehash => {
244 KeyMaterial::Spx(SpxRawPublicKey::read(src)?)
245 }
246 OwnershipKeyAlg::HybridSpxPure | OwnershipKeyAlg::HybridSpxPrehash => {
247 KeyMaterial::Hybrid(HybridRawPublicKey::read(src)?)
248 }
249 _ => {
250 return Err(
251 Error::InvalidPublicKey(anyhow!("Unknown key algorithm {}", kind)).into(),
252 );
253 }
254 };
255 let len = result.len();
256 if buflen != 0 {
257 match len.cmp(&buflen) {
258 Ordering::Less => {
259 let mut discard = vec![0; buflen - len];
260 src.read_exact(&mut discard)?;
261 }
262 Ordering::Greater => {
263 return Err(Error::InvalidPublicKey(anyhow!(
264 "Key type {} does not fit in {} bytes",
265 kind,
266 buflen
267 ))
268 .into());
269 }
270 Ordering::Equal => {}
271 };
272 }
273 Ok(result)
274 }
275
276 pub fn write_length(&self, dest: &mut impl Write, buflen: usize) -> Result<()> {
277 match self {
278 KeyMaterial::Ecdsa(k) => k.write(dest)?,
279 KeyMaterial::Rsa(k) => k.write(dest)?,
280 KeyMaterial::Spx(k) => k.write(dest)?,
281 KeyMaterial::Hybrid(k) => k.write(dest)?,
282 _ => {
283 return Err(Error::InvalidPublicKey(anyhow!("Unknown key type")).into());
284 }
285 };
286
287 if buflen != 0 {
288 let len = self.len();
289 match len.cmp(&buflen) {
290 Ordering::Less => {
291 let zero = vec![0; buflen - len];
292 dest.write_all(&zero)?;
293 }
294 Ordering::Greater => {
295 return Err(Error::InvalidPublicKey(anyhow!(
296 "Key type {} does not fit in {} bytes",
297 self.kind(),
298 buflen
299 ))
300 .into());
301 }
302 Ordering::Equal => {}
303 };
304 }
305 Ok(())
306 }
307}