1use anyhow::Result;
6use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
7use serde_annotate::Annotate;
8use sha2::{Digest, Sha256};
9use sphincsplus::SpxSecretKey;
10use std::convert::TryFrom;
11use std::io::{Read, Write};
12
13use super::ChipDataError;
14use crate::chip::boolean::HardenedBool;
15use crate::chip::rom_error::RomError;
16use crate::crypto::ecdsa::{EcdsaPrivateKey, EcdsaPublicKey, EcdsaRawPublicKey, EcdsaRawSignature};
17use crate::ownership::{DetachedSignature, OwnershipKeyAlg};
18use crate::with_unknown;
19
20with_unknown! {
21 pub enum BootSlot: u32 [default = Self::Unknown] {
22 Unknown = 0,
23 SlotA = u32::from_le_bytes(*b"AA__"),
24 SlotB = u32::from_le_bytes(*b"__BB"),
25 Unspecified = u32::from_le_bytes(*b"UUUU"),
26 }
27
28 pub enum UnlockMode: u32 [default = Self::Unknown] {
30 Unknown = 0,
31 Any = 0x00594e41,
33 Endorsed = 0x4f444e45,
35 Update = 0x00445055,
37 Abort = 0x54524241,
39 }
40
41 pub enum BootSvcKind: u32 [default = Self::Unknown] {
42 Unknown = 0,
43 EmptyRequest = u32::from_le_bytes(*b"EMPT"),
44 EmptyResponse = u32::from_le_bytes(*b"TPME"),
45 MinBl0SecVerRequest = u32::from_le_bytes(*b"MSEC"),
46 MinBl0SecVerResponse = u32::from_le_bytes(*b"CESM"),
47 NextBl0SlotRequest = u32::from_le_bytes(*b"NEXT"),
48 NextBl0SlotResponse = u32::from_le_bytes(*b"TXEN"),
49 OwnershipUnlockRequest = u32::from_le_bytes(*b"UNLK"),
50 OwnershipUnlockResponse = u32::from_le_bytes(*b"KLNU"),
51 OwnershipActivateRequest = u32::from_le_bytes(*b"ACTV"),
52 OwnershipActivateResponse = u32::from_le_bytes(*b"VTCA"),
53 }
54}
55
56impl BootSlot {
57 pub fn opposite(self) -> Result<Self> {
58 match self {
59 BootSlot::SlotA => Ok(BootSlot::SlotB),
60 BootSlot::SlotB => Ok(BootSlot::SlotA),
61 _ => Err(ChipDataError::BadSlot(self).into()),
62 }
63 }
64}
65
66#[derive(Debug, Default, Annotate)]
68pub struct Header {
69 #[annotate(format=hex)]
71 pub digest: [u32; 8],
72 #[annotate(format=hex)]
74 pub identifier: u32,
75 pub kind: BootSvcKind,
77 pub length: u32,
79}
80
81#[derive(Debug, Default, Annotate)]
83pub struct Empty {
84 #[annotate(format=hex)]
85 pub payload: Vec<u32>,
86}
87
88#[derive(Debug, Default, Annotate)]
90pub struct MinBl0SecVerRequest {
91 pub ver: u32,
93}
94
95#[derive(Debug, Default, Annotate)]
97pub struct MinBl0SecVerResponse {
98 pub ver: u32,
100 #[annotate(format = hex)]
102 pub status: RomError,
103}
104
105#[derive(Debug, Default, Annotate)]
107pub struct NextBl0SlotRequest {
108 pub next_bl0_slot: BootSlot,
110 pub primary_bl0_slot: BootSlot,
112}
113
114#[derive(Debug, Default, Annotate)]
116pub struct NextBl0SlotResponse {
117 #[annotate(format = hex)]
119 pub status: RomError,
120 pub primary_bl0_slot: BootSlot,
122}
123
124#[derive(Debug, Default, Annotate)]
126pub struct OwnershipUnlockRequest {
127 pub unlock_mode: UnlockMode,
129 pub din: u64,
131 #[serde(with = "serde_bytes", skip_serializing_if = "Vec::is_empty")]
133 #[annotate(format=hexstr)]
134 pub reserved: Vec<u8>,
135 #[annotate(format=hex)]
137 pub nonce: u64,
138 pub next_owner_key: EcdsaRawPublicKey,
140 #[serde(with = "serde_bytes", skip_serializing_if = "Vec::is_empty")]
142 #[annotate(format=hexstr)]
143 pub hybrid_padding: Vec<u8>,
144 pub signature: EcdsaRawSignature,
146}
147
148#[derive(Debug, Default, Annotate)]
150pub struct OwnershipUnlockResponse {
151 #[annotate(format = hex)]
153 pub status: RomError,
154}
155
156#[derive(Debug, Default, Annotate)]
158pub struct OwnershipActivateRequest {
159 pub primary_bl0_slot: BootSlot,
161 pub din: u64,
163 pub erase_previous: HardenedBool,
165 #[serde(with = "serde_bytes", skip_serializing_if = "Vec::is_empty")]
167 #[annotate(format=hexstr)]
168 pub reserved: Vec<u8>,
169 #[annotate(format=hex)]
171 pub nonce: u64,
172 pub signature: EcdsaRawSignature,
174}
175
176#[derive(Debug, Default, Annotate)]
178pub struct OwnershipActivateResponse {
179 #[annotate(format = hex)]
181 pub status: RomError,
182}
183
184#[derive(Debug, Annotate)]
185pub enum Message {
186 Raw(
187 #[serde(with = "serde_bytes")]
188 #[annotate(format=hexdump)]
189 Vec<u8>,
190 ),
191 Empty(Empty),
192 MinBl0SecVerRequest(MinBl0SecVerRequest),
193 NextBl0SlotRequest(NextBl0SlotRequest),
194 OwnershipUnlockRequest(OwnershipUnlockRequest),
195 OwnershipActivateRequest(OwnershipActivateRequest),
196 MinBl0SecVerResponse(MinBl0SecVerResponse),
197 NextBl0SlotResponse(NextBl0SlotResponse),
198 OwnershipUnlockResponse(OwnershipUnlockResponse),
199 OwnershipActivateResponse(OwnershipActivateResponse),
200}
201
202#[derive(Debug, Annotate)]
203pub struct BootSvc {
204 pub header: Header,
205 pub message: Message,
206}
207
208impl TryFrom<&[u8]> for BootSvc {
209 type Error = ChipDataError;
210 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
211 let header = Header::try_from(buf)?;
212 let len = header.length as usize;
213 if buf.len() - Header::SIZE < len {
214 return Err(ChipDataError::BadSize(len, buf.len()));
215 }
216 let mut digest = Sha256::digest(&buf[Header::HASH_LEN..Header::SIZE]);
217 digest.reverse();
218 if digest[..] == buf[..Header::HASH_LEN] {
219 return Err(ChipDataError::InvalidDigest);
220 }
221 let buf = &buf[Header::SIZE..];
222 let message = match header.kind {
223 BootSvcKind::EmptyRequest => Message::Empty(TryFrom::try_from(buf)?),
224 BootSvcKind::EmptyResponse => Message::Empty(TryFrom::try_from(buf)?),
225 BootSvcKind::MinBl0SecVerRequest => {
226 Message::MinBl0SecVerRequest(TryFrom::try_from(buf)?)
227 }
228 BootSvcKind::MinBl0SecVerResponse => {
229 Message::MinBl0SecVerResponse(TryFrom::try_from(buf)?)
230 }
231 BootSvcKind::NextBl0SlotRequest => Message::NextBl0SlotRequest(TryFrom::try_from(buf)?),
232 BootSvcKind::NextBl0SlotResponse => {
233 Message::NextBl0SlotResponse(TryFrom::try_from(buf)?)
234 }
235 BootSvcKind::OwnershipUnlockRequest => {
236 Message::OwnershipUnlockRequest(TryFrom::try_from(buf)?)
237 }
238 BootSvcKind::OwnershipUnlockResponse => {
239 Message::OwnershipUnlockResponse(TryFrom::try_from(buf)?)
240 }
241 BootSvcKind::OwnershipActivateRequest => {
242 Message::OwnershipActivateRequest(TryFrom::try_from(buf)?)
243 }
244 BootSvcKind::OwnershipActivateResponse => {
245 Message::OwnershipActivateResponse(TryFrom::try_from(buf)?)
246 }
247 _ => Message::Raw(buf.to_vec()),
248 };
249
250 Ok(BootSvc { header, message })
251 }
252}
253
254impl BootSvc {
255 pub fn to_bytes(&self) -> Result<Vec<u8>> {
256 let mut data = Vec::new();
257 self.header.write(&mut data)?;
258 match &self.message {
259 Message::Empty(m) => m.write(&mut data)?,
260 Message::MinBl0SecVerRequest(m) => m.write(&mut data)?,
261 Message::MinBl0SecVerResponse(m) => m.write(&mut data)?,
262 Message::NextBl0SlotRequest(m) => m.write(&mut data)?,
263 Message::NextBl0SlotResponse(m) => m.write(&mut data)?,
264 Message::OwnershipUnlockRequest(m) => m.write(&mut data)?,
265 Message::OwnershipUnlockResponse(m) => m.write(&mut data)?,
266 Message::OwnershipActivateRequest(m) => m.write(&mut data)?,
267 Message::OwnershipActivateResponse(m) => m.write(&mut data)?,
268 Message::Raw(m) => data.extend_from_slice(m.as_slice()),
269 };
270 let mut digest = Sha256::digest(&data[Header::HASH_LEN..]);
271 digest.reverse();
272 data[..Header::HASH_LEN].copy_from_slice(&digest);
273 Ok(data)
274 }
275
276 pub fn min_bl0_sec_ver(ver: u32) -> Self {
277 BootSvc {
278 header: Header {
279 digest: [0u32; 8],
280 identifier: Header::IDENTIFIER,
281 kind: BootSvcKind::MinBl0SecVerRequest,
282 length: (Header::SIZE + MinBl0SecVerRequest::SIZE) as u32,
283 },
284 message: Message::MinBl0SecVerRequest(MinBl0SecVerRequest { ver }),
285 }
286 }
287
288 pub fn next_boot_bl0_slot(primary: BootSlot, next: BootSlot) -> Self {
289 BootSvc {
290 header: Header {
291 digest: [0u32; 8],
292 identifier: Header::IDENTIFIER,
293 kind: BootSvcKind::NextBl0SlotRequest,
294 length: (Header::SIZE + NextBl0SlotRequest::SIZE) as u32,
295 },
296 message: Message::NextBl0SlotRequest(NextBl0SlotRequest {
297 next_bl0_slot: next,
298 primary_bl0_slot: primary,
299 }),
300 }
301 }
302
303 pub fn ownership_unlock(unlock: OwnershipUnlockRequest) -> Self {
304 BootSvc {
305 header: Header {
306 digest: [0u32; 8],
307 identifier: Header::IDENTIFIER,
308 kind: BootSvcKind::OwnershipUnlockRequest,
309 length: (Header::SIZE + OwnershipUnlockRequest::SIZE) as u32,
310 },
311 message: Message::OwnershipUnlockRequest(unlock),
312 }
313 }
314
315 pub fn ownership_activate(activate: OwnershipActivateRequest) -> Self {
316 BootSvc {
317 header: Header {
318 digest: [0u32; 8],
319 identifier: Header::IDENTIFIER,
320 kind: BootSvcKind::OwnershipActivateRequest,
321 length: (Header::SIZE + OwnershipActivateRequest::SIZE) as u32,
322 },
323 message: Message::OwnershipActivateRequest(activate),
324 }
325 }
326}
327
328impl TryFrom<&[u8]> for Header {
329 type Error = ChipDataError;
330 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
331 let mut reader = std::io::Cursor::new(buf);
332 let mut val = Header::default();
333 reader.read_u32_into::<LittleEndian>(&mut val.digest)?;
334 val.identifier = reader.read_u32::<LittleEndian>()?;
335 val.kind = BootSvcKind(reader.read_u32::<LittleEndian>()?);
336 val.length = reader.read_u32::<LittleEndian>()?;
337 Ok(val)
338 }
339}
340impl Header {
341 pub const SIZE: usize = 44;
342 pub const IDENTIFIER: u32 = 0x43565342;
343 const HASH_LEN: usize = 32;
344
345 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
346 for d in self.digest.iter() {
347 dest.write_u32::<LittleEndian>(*d)?;
348 }
349 dest.write_u32::<LittleEndian>(self.identifier)?;
350 dest.write_u32::<LittleEndian>(u32::from(self.kind))?;
351 dest.write_u32::<LittleEndian>(self.length)?;
352 Ok(())
353 }
354}
355
356impl TryFrom<&[u8]> for Empty {
357 type Error = ChipDataError;
358 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
359 let mut reader = std::io::Cursor::new(buf);
360 let mut val = Empty::default();
361 val.payload.resize(64, 0);
362 reader.read_u32_into::<LittleEndian>(&mut val.payload)?;
363 Ok(val)
364 }
365}
366impl Empty {
367 pub const SIZE: usize = 256;
368 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
369 for i in 0..64 {
370 let p = self.payload.get(i).unwrap_or(&0);
371 dest.write_u32::<LittleEndian>(*p)?;
372 }
373 Ok(())
374 }
375}
376
377impl TryFrom<&[u8]> for MinBl0SecVerRequest {
378 type Error = ChipDataError;
379 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
380 let mut reader = std::io::Cursor::new(buf);
381 Ok(MinBl0SecVerRequest {
382 ver: reader.read_u32::<LittleEndian>()?,
383 })
384 }
385}
386impl MinBl0SecVerRequest {
387 pub const SIZE: usize = 4;
388 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
389 dest.write_u32::<LittleEndian>(self.ver)?;
390 Ok(())
391 }
392}
393
394impl TryFrom<&[u8]> for MinBl0SecVerResponse {
395 type Error = ChipDataError;
396 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
397 let mut reader = std::io::Cursor::new(buf);
398 Ok(MinBl0SecVerResponse {
399 ver: reader.read_u32::<LittleEndian>()?,
400 status: RomError(reader.read_u32::<LittleEndian>()?),
401 })
402 }
403}
404impl MinBl0SecVerResponse {
405 pub const SIZE: usize = 8;
406 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
407 dest.write_u32::<LittleEndian>(self.ver)?;
408 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
409 Ok(())
410 }
411}
412
413impl TryFrom<&[u8]> for NextBl0SlotRequest {
414 type Error = ChipDataError;
415 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
416 let mut reader = std::io::Cursor::new(buf);
417 Ok(NextBl0SlotRequest {
418 next_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
419 primary_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
420 })
421 }
422}
423impl NextBl0SlotRequest {
424 pub const SIZE: usize = 8;
425 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
426 dest.write_u32::<LittleEndian>(u32::from(self.next_bl0_slot))?;
427 dest.write_u32::<LittleEndian>(u32::from(self.primary_bl0_slot))?;
428 Ok(())
429 }
430}
431
432impl TryFrom<&[u8]> for NextBl0SlotResponse {
433 type Error = ChipDataError;
434 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
435 let mut reader = std::io::Cursor::new(buf);
436 Ok(NextBl0SlotResponse {
437 status: RomError(reader.read_u32::<LittleEndian>()?),
438 primary_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
439 })
440 }
441}
442impl NextBl0SlotResponse {
443 pub const SIZE: usize = 4;
444 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
445 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
446 Ok(())
447 }
448}
449
450impl TryFrom<&[u8]> for OwnershipUnlockRequest {
451 type Error = ChipDataError;
452 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
453 let mut reader = std::io::Cursor::new(buf);
454 let mut val = Self::default();
455 val.unlock_mode = UnlockMode(reader.read_u32::<LittleEndian>()?);
456 val.din = reader.read_u64::<LittleEndian>()?;
457 val.reserved.resize(Self::RESERVED_SIZE, 0);
458 reader.read_exact(&mut val.reserved)?;
459 val.nonce = reader.read_u64::<LittleEndian>()?;
460 val.next_owner_key = EcdsaRawPublicKey::read(&mut reader).map_err(ChipDataError::Anyhow)?;
461
462 val.hybrid_padding.resize(32, 0);
464 reader.read_exact(&mut val.hybrid_padding)?;
465
466 val.signature = EcdsaRawSignature::read(&mut reader).map_err(ChipDataError::Anyhow)?;
467 Ok(val)
468 }
469}
470impl OwnershipUnlockRequest {
471 pub const SIZE: usize = 212;
472 const RESERVED_SIZE: usize = 8 * std::mem::size_of::<u32>();
473 const SIGNATURE_OFFSET: usize = 148;
474 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
475 dest.write_u32::<LittleEndian>(u32::from(self.unlock_mode))?;
476 dest.write_u64::<LittleEndian>(self.din)?;
477 for i in 0..Self::RESERVED_SIZE {
478 let p = self.reserved.get(i).unwrap_or(&0x00);
479 dest.write_all(std::slice::from_ref(p))?;
480 }
481 dest.write_u64::<LittleEndian>(self.nonce)?;
482 self.next_owner_key.write(dest)?;
483
484 for i in 0..32 {
486 let p = self.hybrid_padding.get(i).unwrap_or(&0x00);
487 dest.write_all(std::slice::from_ref(p))?;
488 }
489
490 self.signature.write(dest)?;
491 Ok(())
492 }
493
494 pub fn set_next_owner_key(&mut self, key: &EcdsaPublicKey) -> Result<()> {
495 self.next_owner_key = EcdsaRawPublicKey::try_from(key)?;
496 Ok(())
497 }
498
499 pub fn sign(&mut self, key: &EcdsaPrivateKey) -> Result<()> {
500 let mut data = Vec::new();
501 self.write(&mut data)?;
502 self.signature = key.digest_and_sign(&data[..Self::SIGNATURE_OFFSET])?;
503 Ok(())
504 }
505
506 pub fn detached_sign(
507 &mut self,
508 algorithm: OwnershipKeyAlg,
509 ecdsa_key: Option<&EcdsaPrivateKey>,
510 spx_key: Option<&SpxSecretKey>,
511 ) -> Result<DetachedSignature> {
512 self.signature = Default::default();
513 let mut data = Vec::new();
514 self.write(&mut data)?;
515 DetachedSignature::new(
516 &data[..Self::SIGNATURE_OFFSET],
517 BootSvcKind::OwnershipUnlockRequest.into(),
518 algorithm,
519 self.nonce,
520 ecdsa_key,
521 spx_key,
522 )
523 }
524}
525
526impl TryFrom<&[u8]> for OwnershipUnlockResponse {
527 type Error = ChipDataError;
528 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
529 let mut reader = std::io::Cursor::new(buf);
530 Ok(OwnershipUnlockResponse {
531 status: RomError(reader.read_u32::<LittleEndian>()?),
532 })
533 }
534}
535impl OwnershipUnlockResponse {
536 pub const SIZE: usize = 4;
537 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
538 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
539 Ok(())
540 }
541}
542
543impl TryFrom<&[u8]> for OwnershipActivateRequest {
544 type Error = ChipDataError;
545 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
546 let mut reader = std::io::Cursor::new(buf);
547 let mut val = Self::default();
548 val.primary_bl0_slot = BootSlot(reader.read_u32::<LittleEndian>()?);
549 val.din = reader.read_u64::<LittleEndian>()?;
550 val.erase_previous = HardenedBool(reader.read_u32::<LittleEndian>()?);
551 val.reserved.resize(Self::RESERVED_SIZE, 0);
552 reader.read_exact(&mut val.reserved)?;
553 val.nonce = reader.read_u64::<LittleEndian>()?;
554 val.signature = EcdsaRawSignature::read(&mut reader).map_err(ChipDataError::Anyhow)?;
555 Ok(val)
556 }
557}
558impl OwnershipActivateRequest {
559 pub const SIZE: usize = 212;
560 const RESERVED_SIZE: usize = 31 * std::mem::size_of::<u32>();
561 const SIGNATURE_OFFSET: usize = 148;
562 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
563 dest.write_u32::<LittleEndian>(u32::from(self.primary_bl0_slot))?;
564 dest.write_u64::<LittleEndian>(self.din)?;
565 dest.write_u32::<LittleEndian>(u32::from(self.erase_previous))?;
566 for i in 0..Self::RESERVED_SIZE {
567 let p = self.reserved.get(i).unwrap_or(&0x00);
568 dest.write_all(std::slice::from_ref(p))?;
569 }
570 dest.write_u64::<LittleEndian>(self.nonce)?;
571 self.signature.write(dest)?;
572 Ok(())
573 }
574
575 pub fn sign(&mut self, key: &EcdsaPrivateKey) -> Result<()> {
576 let mut data = Vec::new();
577 self.write(&mut data)?;
578 self.signature = key.digest_and_sign(&data[..Self::SIGNATURE_OFFSET])?;
579 Ok(())
580 }
581
582 pub fn detached_sign(
583 &mut self,
584 algorithm: OwnershipKeyAlg,
585 ecdsa_key: Option<&EcdsaPrivateKey>,
586 spx_key: Option<&SpxSecretKey>,
587 ) -> Result<DetachedSignature> {
588 self.signature = Default::default();
589 let mut data = Vec::new();
590 self.write(&mut data)?;
591 DetachedSignature::new(
592 &data[..Self::SIGNATURE_OFFSET],
593 BootSvcKind::OwnershipActivateRequest.into(),
594 algorithm,
595 self.nonce,
596 ecdsa_key,
597 spx_key,
598 )
599 }
600}
601
602impl TryFrom<&[u8]> for OwnershipActivateResponse {
603 type Error = ChipDataError;
604 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
605 let mut reader = std::io::Cursor::new(buf);
606 Ok(OwnershipActivateResponse {
607 status: RomError(reader.read_u32::<LittleEndian>()?),
608 })
609 }
610}
611impl OwnershipActivateResponse {
612 pub const SIZE: usize = 4;
613 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
614 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
615 Ok(())
616 }
617}