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_alg: OwnershipKeyAlg,
140 pub next_owner_key: EcdsaRawPublicKey,
142 #[serde(with = "serde_bytes", skip_serializing_if = "Vec::is_empty")]
144 #[annotate(format=hexstr)]
145 pub hybrid_padding: Vec<u8>,
146 pub signature: EcdsaRawSignature,
148}
149
150#[derive(Debug, Default, Annotate)]
152pub struct OwnershipUnlockResponse {
153 #[annotate(format = hex)]
155 pub status: RomError,
156}
157
158#[derive(Debug, Default, Annotate)]
160pub struct OwnershipActivateRequest {
161 pub primary_bl0_slot: BootSlot,
163 pub din: u64,
165 pub erase_previous: HardenedBool,
167 #[serde(with = "serde_bytes", skip_serializing_if = "Vec::is_empty")]
169 #[annotate(format=hexstr)]
170 pub reserved: Vec<u8>,
171 #[annotate(format=hex)]
173 pub nonce: u64,
174 pub signature: EcdsaRawSignature,
176}
177
178#[derive(Debug, Default, Annotate)]
180pub struct OwnershipActivateResponse {
181 #[annotate(format = hex)]
183 pub status: RomError,
184}
185
186#[derive(Debug, Annotate)]
187pub enum Message {
188 Raw(
189 #[serde(with = "serde_bytes")]
190 #[annotate(format=hexdump)]
191 Vec<u8>,
192 ),
193 Empty(Empty),
194 MinBl0SecVerRequest(MinBl0SecVerRequest),
195 NextBl0SlotRequest(NextBl0SlotRequest),
196 OwnershipUnlockRequest(OwnershipUnlockRequest),
197 OwnershipActivateRequest(OwnershipActivateRequest),
198 MinBl0SecVerResponse(MinBl0SecVerResponse),
199 NextBl0SlotResponse(NextBl0SlotResponse),
200 OwnershipUnlockResponse(OwnershipUnlockResponse),
201 OwnershipActivateResponse(OwnershipActivateResponse),
202}
203
204#[derive(Debug, Annotate)]
205pub struct BootSvc {
206 pub header: Header,
207 pub message: Message,
208}
209
210impl TryFrom<&[u8]> for BootSvc {
211 type Error = ChipDataError;
212 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
213 let header = Header::try_from(buf)?;
214 let len = header.length as usize;
215 if buf.len() - Header::SIZE < len {
216 return Err(ChipDataError::BadSize(len, buf.len()));
217 }
218 let mut digest = Sha256::digest(&buf[Header::HASH_LEN..Header::SIZE]);
219 digest.reverse();
220 if digest[..] == buf[..Header::HASH_LEN] {
221 return Err(ChipDataError::InvalidDigest);
222 }
223 let buf = &buf[Header::SIZE..];
224 let message = match header.kind {
225 BootSvcKind::EmptyRequest => Message::Empty(TryFrom::try_from(buf)?),
226 BootSvcKind::EmptyResponse => Message::Empty(TryFrom::try_from(buf)?),
227 BootSvcKind::MinBl0SecVerRequest => {
228 Message::MinBl0SecVerRequest(TryFrom::try_from(buf)?)
229 }
230 BootSvcKind::MinBl0SecVerResponse => {
231 Message::MinBl0SecVerResponse(TryFrom::try_from(buf)?)
232 }
233 BootSvcKind::NextBl0SlotRequest => Message::NextBl0SlotRequest(TryFrom::try_from(buf)?),
234 BootSvcKind::NextBl0SlotResponse => {
235 Message::NextBl0SlotResponse(TryFrom::try_from(buf)?)
236 }
237 BootSvcKind::OwnershipUnlockRequest => {
238 Message::OwnershipUnlockRequest(TryFrom::try_from(buf)?)
239 }
240 BootSvcKind::OwnershipUnlockResponse => {
241 Message::OwnershipUnlockResponse(TryFrom::try_from(buf)?)
242 }
243 BootSvcKind::OwnershipActivateRequest => {
244 Message::OwnershipActivateRequest(TryFrom::try_from(buf)?)
245 }
246 BootSvcKind::OwnershipActivateResponse => {
247 Message::OwnershipActivateResponse(TryFrom::try_from(buf)?)
248 }
249 _ => Message::Raw(buf.to_vec()),
250 };
251
252 Ok(BootSvc { header, message })
253 }
254}
255
256impl BootSvc {
257 pub fn to_bytes(&self) -> Result<Vec<u8>> {
258 let mut data = Vec::new();
259 self.header.write(&mut data)?;
260 match &self.message {
261 Message::Empty(m) => m.write(&mut data)?,
262 Message::MinBl0SecVerRequest(m) => m.write(&mut data)?,
263 Message::MinBl0SecVerResponse(m) => m.write(&mut data)?,
264 Message::NextBl0SlotRequest(m) => m.write(&mut data)?,
265 Message::NextBl0SlotResponse(m) => m.write(&mut data)?,
266 Message::OwnershipUnlockRequest(m) => m.write(&mut data)?,
267 Message::OwnershipUnlockResponse(m) => m.write(&mut data)?,
268 Message::OwnershipActivateRequest(m) => m.write(&mut data)?,
269 Message::OwnershipActivateResponse(m) => m.write(&mut data)?,
270 Message::Raw(m) => data.extend_from_slice(m.as_slice()),
271 };
272 let mut digest = Sha256::digest(&data[Header::HASH_LEN..]);
273 digest.reverse();
274 data[..Header::HASH_LEN].copy_from_slice(&digest);
275 Ok(data)
276 }
277
278 pub fn empty(payload: &[u32]) -> Self {
279 BootSvc {
280 header: Header {
281 digest: [0u32; 8],
282 identifier: Header::IDENTIFIER,
283 kind: BootSvcKind::EmptyRequest,
284 length: (Header::SIZE + Empty::SIZE) as u32,
285 },
286 message: Message::Empty(Empty {
287 payload: payload.to_vec(),
288 }),
289 }
290 }
291
292 pub fn min_bl0_sec_ver(ver: u32) -> Self {
293 BootSvc {
294 header: Header {
295 digest: [0u32; 8],
296 identifier: Header::IDENTIFIER,
297 kind: BootSvcKind::MinBl0SecVerRequest,
298 length: (Header::SIZE + MinBl0SecVerRequest::SIZE) as u32,
299 },
300 message: Message::MinBl0SecVerRequest(MinBl0SecVerRequest { ver }),
301 }
302 }
303
304 pub fn next_boot_bl0_slot(primary: BootSlot, next: BootSlot) -> Self {
305 BootSvc {
306 header: Header {
307 digest: [0u32; 8],
308 identifier: Header::IDENTIFIER,
309 kind: BootSvcKind::NextBl0SlotRequest,
310 length: (Header::SIZE + NextBl0SlotRequest::SIZE) as u32,
311 },
312 message: Message::NextBl0SlotRequest(NextBl0SlotRequest {
313 next_bl0_slot: next,
314 primary_bl0_slot: primary,
315 }),
316 }
317 }
318
319 pub fn ownership_unlock(unlock: OwnershipUnlockRequest) -> Self {
320 BootSvc {
321 header: Header {
322 digest: [0u32; 8],
323 identifier: Header::IDENTIFIER,
324 kind: BootSvcKind::OwnershipUnlockRequest,
325 length: (Header::SIZE + OwnershipUnlockRequest::SIZE) as u32,
326 },
327 message: Message::OwnershipUnlockRequest(unlock),
328 }
329 }
330
331 pub fn ownership_activate(activate: OwnershipActivateRequest) -> Self {
332 BootSvc {
333 header: Header {
334 digest: [0u32; 8],
335 identifier: Header::IDENTIFIER,
336 kind: BootSvcKind::OwnershipActivateRequest,
337 length: (Header::SIZE + OwnershipActivateRequest::SIZE) as u32,
338 },
339 message: Message::OwnershipActivateRequest(activate),
340 }
341 }
342}
343
344impl TryFrom<&[u8]> for Header {
345 type Error = ChipDataError;
346 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
347 let mut reader = std::io::Cursor::new(buf);
348 let mut val = Header::default();
349 reader.read_u32_into::<LittleEndian>(&mut val.digest)?;
350 val.identifier = reader.read_u32::<LittleEndian>()?;
351 val.kind = BootSvcKind(reader.read_u32::<LittleEndian>()?);
352 val.length = reader.read_u32::<LittleEndian>()?;
353 Ok(val)
354 }
355}
356impl Header {
357 pub const SIZE: usize = 44;
358 pub const IDENTIFIER: u32 = 0x43565342;
359 const HASH_LEN: usize = 32;
360
361 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
362 for d in self.digest.iter() {
363 dest.write_u32::<LittleEndian>(*d)?;
364 }
365 dest.write_u32::<LittleEndian>(self.identifier)?;
366 dest.write_u32::<LittleEndian>(u32::from(self.kind))?;
367 dest.write_u32::<LittleEndian>(self.length)?;
368 Ok(())
369 }
370}
371
372impl TryFrom<&[u8]> for Empty {
373 type Error = ChipDataError;
374 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
375 let mut reader = std::io::Cursor::new(buf);
376 let mut val = Empty::default();
377 val.payload.resize(64, 0);
378 reader.read_u32_into::<LittleEndian>(&mut val.payload)?;
379 Ok(val)
380 }
381}
382impl Empty {
383 pub const SIZE: usize = 256;
384 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
385 for i in 0..64 {
386 let p = self.payload.get(i).unwrap_or(&0);
387 dest.write_u32::<LittleEndian>(*p)?;
388 }
389 Ok(())
390 }
391}
392
393impl TryFrom<&[u8]> for MinBl0SecVerRequest {
394 type Error = ChipDataError;
395 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
396 let mut reader = std::io::Cursor::new(buf);
397 Ok(MinBl0SecVerRequest {
398 ver: reader.read_u32::<LittleEndian>()?,
399 })
400 }
401}
402impl MinBl0SecVerRequest {
403 pub const SIZE: usize = 4;
404 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
405 dest.write_u32::<LittleEndian>(self.ver)?;
406 Ok(())
407 }
408}
409
410impl TryFrom<&[u8]> for MinBl0SecVerResponse {
411 type Error = ChipDataError;
412 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
413 let mut reader = std::io::Cursor::new(buf);
414 Ok(MinBl0SecVerResponse {
415 ver: reader.read_u32::<LittleEndian>()?,
416 status: RomError(reader.read_u32::<LittleEndian>()?),
417 })
418 }
419}
420impl MinBl0SecVerResponse {
421 pub const SIZE: usize = 8;
422 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
423 dest.write_u32::<LittleEndian>(self.ver)?;
424 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
425 Ok(())
426 }
427}
428
429impl TryFrom<&[u8]> for NextBl0SlotRequest {
430 type Error = ChipDataError;
431 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
432 let mut reader = std::io::Cursor::new(buf);
433 Ok(NextBl0SlotRequest {
434 next_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
435 primary_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
436 })
437 }
438}
439impl NextBl0SlotRequest {
440 pub const SIZE: usize = 8;
441 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
442 dest.write_u32::<LittleEndian>(u32::from(self.next_bl0_slot))?;
443 dest.write_u32::<LittleEndian>(u32::from(self.primary_bl0_slot))?;
444 Ok(())
445 }
446}
447
448impl TryFrom<&[u8]> for NextBl0SlotResponse {
449 type Error = ChipDataError;
450 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
451 let mut reader = std::io::Cursor::new(buf);
452 Ok(NextBl0SlotResponse {
453 status: RomError(reader.read_u32::<LittleEndian>()?),
454 primary_bl0_slot: BootSlot(reader.read_u32::<LittleEndian>()?),
455 })
456 }
457}
458impl NextBl0SlotResponse {
459 pub const SIZE: usize = 4;
460 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
461 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
462 Ok(())
463 }
464}
465
466impl TryFrom<&[u8]> for OwnershipUnlockRequest {
467 type Error = ChipDataError;
468 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
469 let mut reader = std::io::Cursor::new(buf);
470 let mut val = Self::default();
471 val.unlock_mode = UnlockMode(reader.read_u32::<LittleEndian>()?);
472 val.din = reader.read_u64::<LittleEndian>()?;
473 val.reserved.resize(Self::RESERVED_SIZE, 0);
474 reader.read_exact(&mut val.reserved)?;
475 val.next_owner_alg = OwnershipKeyAlg(reader.read_u32::<LittleEndian>()?);
476 val.nonce = reader.read_u64::<LittleEndian>()?;
477 val.next_owner_key = EcdsaRawPublicKey::read(&mut reader).map_err(ChipDataError::Anyhow)?;
478
479 val.hybrid_padding.resize(32, 0);
481 reader.read_exact(&mut val.hybrid_padding)?;
482
483 val.signature = EcdsaRawSignature::read(&mut reader).map_err(ChipDataError::Anyhow)?;
484 Ok(val)
485 }
486}
487impl OwnershipUnlockRequest {
488 pub const SIZE: usize = 212;
489 const RESERVED_SIZE: usize = 7 * std::mem::size_of::<u32>();
490 const SIGNATURE_OFFSET: usize = 148;
491 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
492 dest.write_u32::<LittleEndian>(u32::from(self.unlock_mode))?;
493 dest.write_u64::<LittleEndian>(self.din)?;
494 for i in 0..Self::RESERVED_SIZE {
495 let p = self.reserved.get(i).unwrap_or(&0x00);
496 dest.write_all(std::slice::from_ref(p))?;
497 }
498 dest.write_u32::<LittleEndian>(u32::from(self.next_owner_alg))?;
499 dest.write_u64::<LittleEndian>(self.nonce)?;
500 self.next_owner_key.write(dest)?;
501
502 for i in 0..32 {
504 let p = self.hybrid_padding.get(i).unwrap_or(&0x00);
505 dest.write_all(std::slice::from_ref(p))?;
506 }
507
508 self.signature.write(dest)?;
509 Ok(())
510 }
511
512 pub fn set_next_owner_key(&mut self, key: &EcdsaPublicKey) -> Result<()> {
513 self.next_owner_key = EcdsaRawPublicKey::try_from(key)?;
514 Ok(())
515 }
516
517 pub fn sign(&mut self, key: &EcdsaPrivateKey) -> Result<()> {
518 let mut data = Vec::new();
519 self.write(&mut data)?;
520 self.signature = key.digest_and_sign(&data[..Self::SIGNATURE_OFFSET])?;
521 Ok(())
522 }
523
524 pub fn detached_sign(
525 &mut self,
526 algorithm: OwnershipKeyAlg,
527 ecdsa_key: Option<&EcdsaPrivateKey>,
528 spx_key: Option<&SpxSecretKey>,
529 ) -> Result<DetachedSignature> {
530 self.signature = Default::default();
531 let mut data = Vec::new();
532 self.write(&mut data)?;
533 DetachedSignature::new(
534 &data[..Self::SIGNATURE_OFFSET],
535 BootSvcKind::OwnershipUnlockRequest.into(),
536 algorithm,
537 self.nonce,
538 ecdsa_key,
539 spx_key,
540 )
541 }
542}
543
544impl TryFrom<&[u8]> for OwnershipUnlockResponse {
545 type Error = ChipDataError;
546 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
547 let mut reader = std::io::Cursor::new(buf);
548 Ok(OwnershipUnlockResponse {
549 status: RomError(reader.read_u32::<LittleEndian>()?),
550 })
551 }
552}
553impl OwnershipUnlockResponse {
554 pub const SIZE: usize = 4;
555 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
556 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
557 Ok(())
558 }
559}
560
561impl TryFrom<&[u8]> for OwnershipActivateRequest {
562 type Error = ChipDataError;
563 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
564 let mut reader = std::io::Cursor::new(buf);
565 let mut val = Self::default();
566 val.primary_bl0_slot = BootSlot(reader.read_u32::<LittleEndian>()?);
567 val.din = reader.read_u64::<LittleEndian>()?;
568 val.erase_previous = HardenedBool(reader.read_u32::<LittleEndian>()?);
569 val.reserved.resize(Self::RESERVED_SIZE, 0);
570 reader.read_exact(&mut val.reserved)?;
571 val.nonce = reader.read_u64::<LittleEndian>()?;
572 val.signature = EcdsaRawSignature::read(&mut reader).map_err(ChipDataError::Anyhow)?;
573 Ok(val)
574 }
575}
576impl OwnershipActivateRequest {
577 pub const SIZE: usize = 212;
578 const RESERVED_SIZE: usize = 31 * std::mem::size_of::<u32>();
579 const SIGNATURE_OFFSET: usize = 148;
580 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
581 dest.write_u32::<LittleEndian>(u32::from(self.primary_bl0_slot))?;
582 dest.write_u64::<LittleEndian>(self.din)?;
583 dest.write_u32::<LittleEndian>(u32::from(self.erase_previous))?;
584 for i in 0..Self::RESERVED_SIZE {
585 let p = self.reserved.get(i).unwrap_or(&0x00);
586 dest.write_all(std::slice::from_ref(p))?;
587 }
588 dest.write_u64::<LittleEndian>(self.nonce)?;
589 self.signature.write(dest)?;
590 Ok(())
591 }
592
593 pub fn sign(&mut self, key: &EcdsaPrivateKey) -> Result<()> {
594 let mut data = Vec::new();
595 self.write(&mut data)?;
596 self.signature = key.digest_and_sign(&data[..Self::SIGNATURE_OFFSET])?;
597 Ok(())
598 }
599
600 pub fn detached_sign(
601 &mut self,
602 algorithm: OwnershipKeyAlg,
603 ecdsa_key: Option<&EcdsaPrivateKey>,
604 spx_key: Option<&SpxSecretKey>,
605 ) -> Result<DetachedSignature> {
606 self.signature = Default::default();
607 let mut data = Vec::new();
608 self.write(&mut data)?;
609 DetachedSignature::new(
610 &data[..Self::SIGNATURE_OFFSET],
611 BootSvcKind::OwnershipActivateRequest.into(),
612 algorithm,
613 self.nonce,
614 ecdsa_key,
615 spx_key,
616 )
617 }
618}
619
620impl TryFrom<&[u8]> for OwnershipActivateResponse {
621 type Error = ChipDataError;
622 fn try_from(buf: &[u8]) -> std::result::Result<Self, Self::Error> {
623 let mut reader = std::io::Cursor::new(buf);
624 Ok(OwnershipActivateResponse {
625 status: RomError(reader.read_u32::<LittleEndian>()?),
626 })
627 }
628}
629impl OwnershipActivateResponse {
630 pub const SIZE: usize = 4;
631 pub fn write(&self, dest: &mut impl Write) -> Result<()> {
632 dest.write_u32::<LittleEndian>(u32::from(self.status))?;
633 Ok(())
634 }
635}