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 empty(payload: &[u32]) -> Self {
277 BootSvc {
278 header: Header {
279 digest: [0u32; 8],
280 identifier: Header::IDENTIFIER,
281 kind: BootSvcKind::EmptyRequest,
282 length: (Header::SIZE + Empty::SIZE) as u32,
283 },
284 message: Message::Empty(Empty {
285 payload: payload.to_vec(),
286 }),
287 }
288 }
289
290 pub fn min_bl0_sec_ver(ver: u32) -> Self {
291 BootSvc {
292 header: Header {
293 digest: [0u32; 8],
294 identifier: Header::IDENTIFIER,
295 kind: BootSvcKind::MinBl0SecVerRequest,
296 length: (Header::SIZE + MinBl0SecVerRequest::SIZE) as u32,
297 },
298 message: Message::MinBl0SecVerRequest(MinBl0SecVerRequest { ver }),
299 }
300 }
301
302 pub fn next_boot_bl0_slot(primary: BootSlot, next: BootSlot) -> Self {
303 BootSvc {
304 header: Header {
305 digest: [0u32; 8],
306 identifier: Header::IDENTIFIER,
307 kind: BootSvcKind::NextBl0SlotRequest,
308 length: (Header::SIZE + NextBl0SlotRequest::SIZE) as u32,
309 },
310 message: Message::NextBl0SlotRequest(NextBl0SlotRequest {
311 next_bl0_slot: next,
312 primary_bl0_slot: primary,
313 }),
314 }
315 }
316
317 pub fn ownership_unlock(unlock: OwnershipUnlockRequest) -> Self {
318 BootSvc {
319 header: Header {
320 digest: [0u32; 8],
321 identifier: Header::IDENTIFIER,
322 kind: BootSvcKind::OwnershipUnlockRequest,
323 length: (Header::SIZE + OwnershipUnlockRequest::SIZE) as u32,
324 },
325 message: Message::OwnershipUnlockRequest(unlock),
326 }
327 }
328
329 pub fn ownership_activate(activate: OwnershipActivateRequest) -> Self {
330 BootSvc {
331 header: Header {
332 digest: [0u32; 8],
333 identifier: Header::IDENTIFIER,
334 kind: BootSvcKind::OwnershipActivateRequest,
335 length: (Header::SIZE + OwnershipActivateRequest::SIZE) as u32,
336 },
337 message: Message::OwnershipActivateRequest(activate),
338 }
339 }
340}
341
342impl TryFrom<&[u8]> for Header {
343 type Error = ChipDataError;
344 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
345 let mut reader = std::io::Cursor::new(buf);
346 let mut val = Header::default();
347 reader.read_u32_into::<LittleEndian>(&mut val.digest)?;
348 val.identifier = reader.read_u32::<LittleEndian>()?;
349 val.kind = BootSvcKind(reader.read_u32::<LittleEndian>()?);
350 val.length = reader.read_u32::<LittleEndian>()?;
351 Ok(val)
352 }
353}
354impl Header {
355 pub const SIZE: usize = 44;
356 pub const IDENTIFIER: u32 = 0x43565342;
357 const HASH_LEN: usize = 32;
358
359 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
360 for d in self.digest.iter() {
361 dest.write_u32::<LittleEndian>(*d)?;
362 }
363 dest.write_u32::<LittleEndian>(self.identifier)?;
364 dest.write_u32::<LittleEndian>(u32::from(self.kind))?;
365 dest.write_u32::<LittleEndian>(self.length)?;
366 Ok(())
367 }
368}
369
370impl TryFrom<&[u8]> for Empty {
371 type Error = ChipDataError;
372 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
373 let mut reader = std::io::Cursor::new(buf);
374 let mut val = Empty::default();
375 val.payload.resize(64, 0);
376 reader.read_u32_into::<LittleEndian>(&mut val.payload)?;
377 Ok(val)
378 }
379}
380impl Empty {
381 pub const SIZE: usize = 256;
382 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
383 for i in 0..64 {
384 let p = self.payload.get(i).unwrap_or(&0);
385 dest.write_u32::<LittleEndian>(*p)?;
386 }
387 Ok(())
388 }
389}
390
391impl TryFrom<&[u8]> for MinBl0SecVerRequest {
392 type Error = ChipDataError;
393 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
394 let mut reader = std::io::Cursor::new(buf);
395 Ok(MinBl0SecVerRequest {
396 ver: reader.read_u32::<LittleEndian>()?,
397 })
398 }
399}
400impl MinBl0SecVerRequest {
401 pub const SIZE: usize = 4;
402 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
403 dest.write_u32::<LittleEndian>(self.ver)?;
404 Ok(())
405 }
406}
407
408impl TryFrom<&[u8]> for MinBl0SecVerResponse {
409 type Error = ChipDataError;
410 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
411 let mut reader = std::io::Cursor::new(buf);
412 Ok(MinBl0SecVerResponse {
413 ver: reader.read_u32::<LittleEndian>()?,
414 status: RomError(reader.read_u32::<LittleEndian>()?),
415 })
416 }
417}
418impl MinBl0SecVerResponse {
419 pub const SIZE: usize = 8;
420 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
421 dest.write_u32::<LittleEndian>(self.ver)?;
422 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
423 Ok(())
424 }
425}
426
427impl TryFrom<&[u8]> for NextBl0SlotRequest {
428 type Error = ChipDataError;
429 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
430 let mut reader = std::io::Cursor::new(buf);
431 Ok(NextBl0SlotRequest {
432 next_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
433 primary_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
434 })
435 }
436}
437impl NextBl0SlotRequest {
438 pub const SIZE: usize = 8;
439 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
440 dest.write_u32::<LittleEndian>(u32::from(self.next_bl0_slot))?;
441 dest.write_u32::<LittleEndian>(u32::from(self.primary_bl0_slot))?;
442 Ok(())
443 }
444}
445
446impl TryFrom<&[u8]> for NextBl0SlotResponse {
447 type Error = ChipDataError;
448 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
449 let mut reader = std::io::Cursor::new(buf);
450 Ok(NextBl0SlotResponse {
451 status: RomError(reader.read_u32::<LittleEndian>()?),
452 primary_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
453 })
454 }
455}
456impl NextBl0SlotResponse {
457 pub const SIZE: usize = 4;
458 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
459 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
460 Ok(())
461 }
462}
463
464impl TryFrom<&[u8]> for OwnershipUnlockRequest {
465 type Error = ChipDataError;
466 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
467 let mut reader = std::io::Cursor::new(buf);
468 let mut val = Self::default();
469 val.unlock_mode = UnlockMode(reader.read_u32::<LittleEndian>()?);
470 val.din = reader.read_u64::<LittleEndian>()?;
471 val.reserved.resize(Self::RESERVED_SIZE, 0);
472 reader.read_exact(&mut val.reserved)?;
473 val.nonce = reader.read_u64::<LittleEndian>()?;
474 val.next_owner_key = EcdsaRawPublicKey::read(&mut reader).map_err(ChipDataError::Anyhow)?;
475
476 val.hybrid_padding.resize(32, 0);
478 reader.read_exact(&mut val.hybrid_padding)?;
479
480 val.signature = EcdsaRawSignature::read(&mut reader).map_err(ChipDataError::Anyhow)?;
481 Ok(val)
482 }
483}
484impl OwnershipUnlockRequest {
485 pub const SIZE: usize = 212;
486 const RESERVED_SIZE: usize = 8 * std::mem::size_of::<u32>();
487 const SIGNATURE_OFFSET: usize = 148;
488 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
489 dest.write_u32::<LittleEndian>(u32::from(self.unlock_mode))?;
490 dest.write_u64::<LittleEndian>(self.din)?;
491 for i in 0..Self::RESERVED_SIZE {
492 let p = self.reserved.get(i).unwrap_or(&0x00);
493 dest.write_all(std::slice::from_ref(p))?;
494 }
495 dest.write_u64::<LittleEndian>(self.nonce)?;
496 self.next_owner_key.write(dest)?;
497
498 for i in 0..32 {
500 let p = self.hybrid_padding.get(i).unwrap_or(&0x00);
501 dest.write_all(std::slice::from_ref(p))?;
502 }
503
504 self.signature.write(dest)?;
505 Ok(())
506 }
507
508 pub fn set_next_owner_key(&mut self, key: &EcdsaPublicKey) -> Result<()> {
509 self.next_owner_key = EcdsaRawPublicKey::try_from(key)?;
510 Ok(())
511 }
512
513 pub fn sign(&mut self, key: &EcdsaPrivateKey) -> Result<()> {
514 let mut data = Vec::new();
515 self.write(&mut data)?;
516 self.signature = key.digest_and_sign(&data[..Self::SIGNATURE_OFFSET])?;
517 Ok(())
518 }
519
520 pub fn detached_sign(
521 &mut self,
522 algorithm: OwnershipKeyAlg,
523 ecdsa_key: Option<&EcdsaPrivateKey>,
524 spx_key: Option<&SpxSecretKey>,
525 ) -> Result<DetachedSignature> {
526 self.signature = Default::default();
527 let mut data = Vec::new();
528 self.write(&mut data)?;
529 DetachedSignature::new(
530 &data[..Self::SIGNATURE_OFFSET],
531 BootSvcKind::OwnershipUnlockRequest.into(),
532 algorithm,
533 self.nonce,
534 ecdsa_key,
535 spx_key,
536 )
537 }
538}
539
540impl TryFrom<&[u8]> for OwnershipUnlockResponse {
541 type Error = ChipDataError;
542 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
543 let mut reader = std::io::Cursor::new(buf);
544 Ok(OwnershipUnlockResponse {
545 status: RomError(reader.read_u32::<LittleEndian>()?),
546 })
547 }
548}
549impl OwnershipUnlockResponse {
550 pub const SIZE: usize = 4;
551 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
552 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
553 Ok(())
554 }
555}
556
557impl TryFrom<&[u8]> for OwnershipActivateRequest {
558 type Error = ChipDataError;
559 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
560 let mut reader = std::io::Cursor::new(buf);
561 let mut val = Self::default();
562 val.primary_bl0_slot = BootSlot(reader.read_u32::<LittleEndian>()?);
563 val.din = reader.read_u64::<LittleEndian>()?;
564 val.erase_previous = HardenedBool(reader.read_u32::<LittleEndian>()?);
565 val.reserved.resize(Self::RESERVED_SIZE, 0);
566 reader.read_exact(&mut val.reserved)?;
567 val.nonce = reader.read_u64::<LittleEndian>()?;
568 val.signature = EcdsaRawSignature::read(&mut reader).map_err(ChipDataError::Anyhow)?;
569 Ok(val)
570 }
571}
572impl OwnershipActivateRequest {
573 pub const SIZE: usize = 212;
574 const RESERVED_SIZE: usize = 31 * std::mem::size_of::<u32>();
575 const SIGNATURE_OFFSET: usize = 148;
576 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
577 dest.write_u32::<LittleEndian>(u32::from(self.primary_bl0_slot))?;
578 dest.write_u64::<LittleEndian>(self.din)?;
579 dest.write_u32::<LittleEndian>(u32::from(self.erase_previous))?;
580 for i in 0..Self::RESERVED_SIZE {
581 let p = self.reserved.get(i).unwrap_or(&0x00);
582 dest.write_all(std::slice::from_ref(p))?;
583 }
584 dest.write_u64::<LittleEndian>(self.nonce)?;
585 self.signature.write(dest)?;
586 Ok(())
587 }
588
589 pub fn sign(&mut self, key: &EcdsaPrivateKey) -> Result<()> {
590 let mut data = Vec::new();
591 self.write(&mut data)?;
592 self.signature = key.digest_and_sign(&data[..Self::SIGNATURE_OFFSET])?;
593 Ok(())
594 }
595
596 pub fn detached_sign(
597 &mut self,
598 algorithm: OwnershipKeyAlg,
599 ecdsa_key: Option<&EcdsaPrivateKey>,
600 spx_key: Option<&SpxSecretKey>,
601 ) -> Result<DetachedSignature> {
602 self.signature = Default::default();
603 let mut data = Vec::new();
604 self.write(&mut data)?;
605 DetachedSignature::new(
606 &data[..Self::SIGNATURE_OFFSET],
607 BootSvcKind::OwnershipActivateRequest.into(),
608 algorithm,
609 self.nonce,
610 ecdsa_key,
611 spx_key,
612 )
613 }
614}
615
616impl TryFrom<&[u8]> for OwnershipActivateResponse {
617 type Error = ChipDataError;
618 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
619 let mut reader = std::io::Cursor::new(buf);
620 Ok(OwnershipActivateResponse {
621 status: RomError(reader.read_u32::<LittleEndian>()?),
622 })
623 }
624}
625impl OwnershipActivateResponse {
626 pub const SIZE: usize = 4;
627 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
628 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
629 Ok(())
630 }
631}