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