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