1use core::fmt;
8use core::mem::size_of;
9
10const NUM_STORAGE_PERMISSIONS: usize = 8;
13
14pub enum InitialTbfParseError {
17    UnableToParse,
22
23    InvalidHeader(u32),
28}
29
30impl From<core::array::TryFromSliceError> for InitialTbfParseError {
31    fn from(_error: core::array::TryFromSliceError) -> Self {
35        InitialTbfParseError::UnableToParse
36    }
37}
38
39pub enum TbfParseError {
41    NotEnoughFlash,
43
44    UnsupportedVersion(u16),
46
47    ChecksumMismatch(u32, u32),
51
52    BadTlvEntry(usize),
56
57    BadProcessName,
60
61    InternalError,
67
68    TooManyEntries(usize),
73}
74
75impl From<core::array::TryFromSliceError> for TbfParseError {
76    fn from(_error: core::array::TryFromSliceError) -> Self {
80        TbfParseError::InternalError
81    }
82}
83
84impl fmt::Debug for TbfParseError {
85    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86        match self {
87            TbfParseError::NotEnoughFlash => write!(f, "Buffer too short to parse TBF header"),
88            TbfParseError::UnsupportedVersion(version) => {
89                write!(f, "TBF version {} unsupported", version)
90            }
91            TbfParseError::ChecksumMismatch(app, calc) => write!(
92                f,
93                "Checksum verification failed: app:{:#x}, calc:{:#x}",
94                app, calc
95            ),
96            TbfParseError::BadTlvEntry(tipe) => write!(f, "TLV entry type {} is invalid", tipe),
97            TbfParseError::BadProcessName => write!(f, "Process name not UTF-8"),
98            TbfParseError::InternalError => write!(f, "Internal kernel error. This is a bug."),
99            TbfParseError::TooManyEntries(tipe) => {
100                write!(
101                    f,
102                    "There are too many variable entries of {} for Tock to parse",
103                    tipe
104                )
105            }
106        }
107    }
108}
109
110#[derive(Clone, Copy, Debug)]
114pub struct TbfHeaderV2Base {
115    pub(crate) version: u16,
116    pub(crate) header_size: u16,
117    pub(crate) total_size: u32,
118    pub(crate) flags: u32,
119    pub(crate) checksum: u32,
120}
121
122#[derive(Clone, Copy, Debug)]
124pub enum TbfHeaderTypes {
125    TbfHeaderMain = 1,
126    TbfHeaderWriteableFlashRegions = 2,
127    TbfHeaderPackageName = 3,
128    TbfHeaderFixedAddresses = 5,
129    TbfHeaderPermissions = 6,
130    TbfHeaderStoragePermissions = 7,
131    TbfHeaderKernelVersion = 8,
132    TbfHeaderProgram = 9,
133    TbfHeaderShortId = 10,
134    TbfFooterCredentials = 128,
135
136    Unknown,
140}
141
142#[derive(Clone, Copy, Debug)]
144pub struct TbfTlv {
145    pub(crate) tipe: TbfHeaderTypes,
146    pub(crate) length: u16,
147}
148
149#[derive(Clone, Copy, Debug)]
157pub struct TbfHeaderV2Main {
158    init_fn_offset: u32,
159    protected_trailer_size: u32,
160    minimum_ram_size: u32,
161}
162
163#[derive(Clone, Copy, Debug)]
173pub struct TbfHeaderV2Program {
174    init_fn_offset: u32,
175    protected_trailer_size: u32,
176    minimum_ram_size: u32,
177    binary_end_offset: u32,
178    version: u32,
179}
180
181#[derive(Clone, Copy, Debug, Default)]
186pub struct TbfHeaderV2WriteableFlashRegion {
187    writeable_flash_region_offset: u32,
188    writeable_flash_region_size: u32,
189}
190
191#[derive(Clone, Copy, Debug, Default)]
204pub struct TbfHeaderV2FixedAddresses {
205    start_process_ram: u32,
209    start_process_flash: u32,
213}
214
215#[derive(Clone, Copy, Debug, Default)]
216struct TbfHeaderDriverPermission {
217    driver_number: u32,
218    offset: u32,
219    allowed_commands: u64,
220}
221
222#[derive(Clone, Copy, Debug)]
224pub struct TbfHeaderV2Permissions<const L: usize> {
225    length: u16,
226    perms: [TbfHeaderDriverPermission; L],
227}
228
229#[derive(Clone, Copy, Debug)]
231pub struct TbfHeaderV2StoragePermissions<const L: usize> {
232    write_id: Option<core::num::NonZeroU32>,
233    read_length: u16,
234    read_ids: [u32; L],
235    modify_length: u16,
236    modify_ids: [u32; L],
237}
238
239#[derive(Clone, Copy, Debug)]
240pub struct TbfHeaderV2KernelVersion {
241    major: u16,
242    minor: u16,
243}
244
245#[derive(Clone, Copy, Debug)]
249pub struct TbfHeaderV2ShortId {
250    short_id: Option<core::num::NonZeroU32>,
251}
252
253#[derive(Clone, Copy, Debug, Eq, PartialEq)]
254pub enum TbfFooterV2CredentialsType {
255    Reserved = 0,
256    Rsa3072Key = 1,
257    Rsa4096Key = 2,
258    SHA256 = 3,
259    SHA384 = 4,
260    SHA512 = 5,
261    EcdsaNistP256 = 6,
262}
263
264#[derive(Clone, Copy, Debug)]
265pub struct TbfFooterV2Credentials {
266    format: TbfFooterV2CredentialsType,
267    data: &'static [u8],
268}
269
270impl TbfFooterV2Credentials {
271    pub fn format(&self) -> TbfFooterV2CredentialsType {
272        self.format
273    }
274
275    pub fn data(&self) -> &'static [u8] {
276        self.data
277    }
278}
279
280impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Base {
283    type Error = TbfParseError;
284
285    fn try_from(b: &[u8]) -> Result<TbfHeaderV2Base, Self::Error> {
286        if b.len() < 16 {
287            return Err(TbfParseError::InternalError);
288        }
289        Ok(TbfHeaderV2Base {
290            version: u16::from_le_bytes(
291                b.get(0..2)
292                    .ok_or(TbfParseError::InternalError)?
293                    .try_into()?,
294            ),
295            header_size: u16::from_le_bytes(
296                b.get(2..4)
297                    .ok_or(TbfParseError::InternalError)?
298                    .try_into()?,
299            ),
300            total_size: u32::from_le_bytes(
301                b.get(4..8)
302                    .ok_or(TbfParseError::InternalError)?
303                    .try_into()?,
304            ),
305            flags: u32::from_le_bytes(
306                b.get(8..12)
307                    .ok_or(TbfParseError::InternalError)?
308                    .try_into()?,
309            ),
310            checksum: u32::from_le_bytes(
311                b.get(12..16)
312                    .ok_or(TbfParseError::InternalError)?
313                    .try_into()?,
314            ),
315        })
316    }
317}
318
319impl core::convert::TryFrom<u16> for TbfHeaderTypes {
320    type Error = TbfParseError;
321
322    fn try_from(h: u16) -> Result<TbfHeaderTypes, Self::Error> {
323        match h {
324            1 => Ok(TbfHeaderTypes::TbfHeaderMain),
325            2 => Ok(TbfHeaderTypes::TbfHeaderWriteableFlashRegions),
326            3 => Ok(TbfHeaderTypes::TbfHeaderPackageName),
327            5 => Ok(TbfHeaderTypes::TbfHeaderFixedAddresses),
328            6 => Ok(TbfHeaderTypes::TbfHeaderPermissions),
329            7 => Ok(TbfHeaderTypes::TbfHeaderStoragePermissions),
330            8 => Ok(TbfHeaderTypes::TbfHeaderKernelVersion),
331            9 => Ok(TbfHeaderTypes::TbfHeaderProgram),
332            10 => Ok(TbfHeaderTypes::TbfHeaderShortId),
333            128 => Ok(TbfHeaderTypes::TbfFooterCredentials),
334            _ => Ok(TbfHeaderTypes::Unknown),
335        }
336    }
337}
338
339impl core::convert::TryFrom<&[u8]> for TbfTlv {
340    type Error = TbfParseError;
341
342    fn try_from(b: &[u8]) -> Result<TbfTlv, Self::Error> {
343        Ok(TbfTlv {
344            tipe: u16::from_le_bytes(
345                b.get(0..2)
346                    .ok_or(TbfParseError::InternalError)?
347                    .try_into()?,
348            )
349            .try_into()?,
350            length: u16::from_le_bytes(
351                b.get(2..4)
352                    .ok_or(TbfParseError::InternalError)?
353                    .try_into()?,
354            ),
355        })
356    }
357}
358
359impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Main {
360    type Error = TbfParseError;
361
362    fn try_from(b: &[u8]) -> Result<TbfHeaderV2Main, Self::Error> {
363        if b.len() < 12 {
365            return Err(TbfParseError::InternalError);
366        }
367        Ok(TbfHeaderV2Main {
368            init_fn_offset: u32::from_le_bytes(
369                b.get(0..4)
370                    .ok_or(TbfParseError::InternalError)?
371                    .try_into()?,
372            ),
373            protected_trailer_size: u32::from_le_bytes(
374                b.get(4..8)
375                    .ok_or(TbfParseError::InternalError)?
376                    .try_into()?,
377            ),
378            minimum_ram_size: u32::from_le_bytes(
379                b.get(8..12)
380                    .ok_or(TbfParseError::InternalError)?
381                    .try_into()?,
382            ),
383        })
384    }
385}
386
387impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Program {
388    type Error = TbfParseError;
389    fn try_from(b: &[u8]) -> Result<TbfHeaderV2Program, Self::Error> {
390        if b.len() < 20 {
392            return Err(TbfParseError::InternalError);
393        }
394        Ok(TbfHeaderV2Program {
395            init_fn_offset: u32::from_le_bytes(
396                b.get(0..4)
397                    .ok_or(TbfParseError::InternalError)?
398                    .try_into()?,
399            ),
400            protected_trailer_size: u32::from_le_bytes(
401                b.get(4..8)
402                    .ok_or(TbfParseError::InternalError)?
403                    .try_into()?,
404            ),
405            minimum_ram_size: u32::from_le_bytes(
406                b.get(8..12)
407                    .ok_or(TbfParseError::InternalError)?
408                    .try_into()?,
409            ),
410            binary_end_offset: u32::from_le_bytes(
411                b.get(12..16)
412                    .ok_or(TbfParseError::InternalError)?
413                    .try_into()?,
414            ),
415            version: u32::from_le_bytes(
416                b.get(16..20)
417                    .ok_or(TbfParseError::InternalError)?
418                    .try_into()?,
419            ),
420        })
421    }
422}
423
424impl core::convert::TryFrom<&[u8]> for TbfHeaderV2WriteableFlashRegion {
425    type Error = TbfParseError;
426
427    fn try_from(b: &[u8]) -> Result<TbfHeaderV2WriteableFlashRegion, Self::Error> {
428        Ok(TbfHeaderV2WriteableFlashRegion {
429            writeable_flash_region_offset: u32::from_le_bytes(
430                b.get(0..4)
431                    .ok_or(TbfParseError::InternalError)?
432                    .try_into()?,
433            ),
434            writeable_flash_region_size: u32::from_le_bytes(
435                b.get(4..8)
436                    .ok_or(TbfParseError::InternalError)?
437                    .try_into()?,
438            ),
439        })
440    }
441}
442
443impl core::convert::TryFrom<&[u8]> for TbfHeaderV2FixedAddresses {
444    type Error = TbfParseError;
445
446    fn try_from(b: &[u8]) -> Result<TbfHeaderV2FixedAddresses, Self::Error> {
447        Ok(TbfHeaderV2FixedAddresses {
448            start_process_ram: u32::from_le_bytes(
449                b.get(0..4)
450                    .ok_or(TbfParseError::InternalError)?
451                    .try_into()?,
452            ),
453            start_process_flash: u32::from_le_bytes(
454                b.get(4..8)
455                    .ok_or(TbfParseError::InternalError)?
456                    .try_into()?,
457            ),
458        })
459    }
460}
461
462impl core::convert::TryFrom<&[u8]> for TbfHeaderDriverPermission {
463    type Error = TbfParseError;
464
465    fn try_from(b: &[u8]) -> Result<TbfHeaderDriverPermission, Self::Error> {
466        if b.len() < 16 {
468            return Err(TbfParseError::InternalError);
469        }
470        Ok(TbfHeaderDriverPermission {
471            driver_number: u32::from_le_bytes(
472                b.get(0..4)
473                    .ok_or(TbfParseError::InternalError)?
474                    .try_into()?,
475            ),
476            offset: u32::from_le_bytes(
477                b.get(4..8)
478                    .ok_or(TbfParseError::InternalError)?
479                    .try_into()?,
480            ),
481            allowed_commands: u64::from_le_bytes(
482                b.get(8..16)
483                    .ok_or(TbfParseError::InternalError)?
484                    .try_into()?,
485            ),
486        })
487    }
488}
489
490impl<const L: usize> core::convert::TryFrom<&[u8]> for TbfHeaderV2StoragePermissions<L> {
491    type Error = TbfParseError;
492
493    fn try_from(b: &[u8]) -> Result<TbfHeaderV2StoragePermissions<L>, Self::Error> {
494        let mut read_end = 6;
495
496        let write_id = core::num::NonZeroU32::new(u32::from_le_bytes(
497            b.get(0..4)
498                .ok_or(TbfParseError::NotEnoughFlash)?
499                .try_into()?,
500        ));
501
502        let read_length = u16::from_le_bytes(
503            b.get(4..6)
504                .ok_or(TbfParseError::NotEnoughFlash)?
505                .try_into()?,
506        );
507
508        let mut read_ids: [u32; L] = [0; L];
509        for i in 0..read_length as usize {
510            let start = 6 + (i * size_of::<u32>());
511            read_end = start + size_of::<u32>();
512            if let Some(read_id) = read_ids.get_mut(i) {
513                *read_id = u32::from_le_bytes(
514                    b.get(start..read_end)
515                        .ok_or(TbfParseError::NotEnoughFlash)?
516                        .try_into()?,
517                );
518            } else {
519                return Err(TbfParseError::BadTlvEntry(
520                    TbfHeaderTypes::TbfHeaderStoragePermissions as usize,
521                ));
522            }
523        }
524
525        let modify_length = u16::from_le_bytes(
526            b.get(read_end..(read_end + 2))
527                .ok_or(TbfParseError::NotEnoughFlash)?
528                .try_into()?,
529        );
530
531        let mut modify_ids: [u32; L] = [0; L];
532        for i in 0..modify_length as usize {
533            let start = read_end + 2 + (i * size_of::<u32>());
534            let modify_end = start + size_of::<u32>();
535            if let Some(modify_id) = modify_ids.get_mut(i) {
536                *modify_id = u32::from_le_bytes(
537                    b.get(start..modify_end)
538                        .ok_or(TbfParseError::NotEnoughFlash)?
539                        .try_into()?,
540                );
541            } else {
542                return Err(TbfParseError::BadTlvEntry(
543                    TbfHeaderTypes::TbfHeaderStoragePermissions as usize,
544                ));
545            }
546        }
547
548        Ok(TbfHeaderV2StoragePermissions {
549            write_id,
550            read_length,
551            read_ids,
552            modify_length,
553            modify_ids,
554        })
555    }
556}
557
558impl core::convert::TryFrom<&[u8]> for TbfHeaderV2KernelVersion {
559    type Error = TbfParseError;
560
561    fn try_from(b: &[u8]) -> Result<TbfHeaderV2KernelVersion, Self::Error> {
562        Ok(TbfHeaderV2KernelVersion {
563            major: u16::from_le_bytes(
564                b.get(0..2)
565                    .ok_or(TbfParseError::InternalError)?
566                    .try_into()?,
567            ),
568            minor: u16::from_le_bytes(
569                b.get(2..4)
570                    .ok_or(TbfParseError::InternalError)?
571                    .try_into()?,
572            ),
573        })
574    }
575}
576
577impl core::convert::TryFrom<&[u8]> for TbfHeaderV2ShortId {
578    type Error = TbfParseError;
579
580    fn try_from(b: &[u8]) -> Result<TbfHeaderV2ShortId, Self::Error> {
581        Ok(TbfHeaderV2ShortId {
582            short_id: core::num::NonZeroU32::new(u32::from_le_bytes(
583                b.get(0..4)
584                    .ok_or(TbfParseError::InternalError)?
585                    .try_into()?,
586            )),
587        })
588    }
589}
590
591impl core::convert::TryFrom<&'static [u8]> for TbfFooterV2Credentials {
592    type Error = TbfParseError;
593
594    fn try_from(b: &'static [u8]) -> Result<TbfFooterV2Credentials, Self::Error> {
595        let format = u32::from_le_bytes(
596            b.get(0..4)
597                .ok_or(TbfParseError::InternalError)?
598                .try_into()?,
599        );
600        let ftype = match format {
601            0 => TbfFooterV2CredentialsType::Reserved,
602            1 => TbfFooterV2CredentialsType::Rsa3072Key,
603            2 => TbfFooterV2CredentialsType::Rsa4096Key,
604            3 => TbfFooterV2CredentialsType::SHA256,
605            4 => TbfFooterV2CredentialsType::SHA384,
606            5 => TbfFooterV2CredentialsType::SHA512,
607            6 => TbfFooterV2CredentialsType::EcdsaNistP256,
608            _ => {
609                return Err(TbfParseError::BadTlvEntry(
610                    TbfHeaderTypes::TbfFooterCredentials as usize,
611                ));
612            }
613        };
614        let length = match ftype {
615            TbfFooterV2CredentialsType::Reserved => 0,
616            TbfFooterV2CredentialsType::Rsa3072Key => 768,
617            TbfFooterV2CredentialsType::Rsa4096Key => 1024,
618            TbfFooterV2CredentialsType::SHA256 => 32,
619            TbfFooterV2CredentialsType::SHA384 => 48,
620            TbfFooterV2CredentialsType::SHA512 => 64,
621            TbfFooterV2CredentialsType::EcdsaNistP256 => 64,
622        };
623        let data = &b
624            .get(4..(length + 4))
625            .ok_or(TbfParseError::NotEnoughFlash)?;
626        Ok(TbfFooterV2Credentials {
627            format: ftype,
628            data,
629        })
630    }
631}
632
633pub enum CommandPermissions {
637    NoPermsAtAll,
639    NoPermsThisDriver,
642    Mask(u64),
645}
646
647#[derive(Clone, Copy, Debug)]
653pub struct TbfHeaderV2<'a> {
654    pub(crate) base: TbfHeaderV2Base,
655    pub(crate) main: Option<TbfHeaderV2Main>,
656    pub(crate) program: Option<TbfHeaderV2Program>,
657    pub(crate) package_name: Option<&'a str>,
658    pub(crate) writeable_regions: Option<&'a [u8]>,
659    pub(crate) fixed_addresses: Option<&'a [u8]>,
660    pub(crate) permissions: Option<&'a [u8]>,
661    pub(crate) storage_permissions: Option<&'a [u8]>,
662    pub(crate) kernel_version: Option<TbfHeaderV2KernelVersion>,
663    pub(crate) short_id: Option<TbfHeaderV2ShortId>,
664}
665
666#[derive(Debug)]
673pub enum TbfHeader<'a> {
674    TbfHeaderV2(TbfHeaderV2<'a>),
675    Padding(TbfHeaderV2Base),
676}
677
678impl<'a> TbfHeader<'a> {
679    pub fn length(&self) -> u16 {
681        match *self {
682            TbfHeader::TbfHeaderV2(hd) => hd.base.header_size,
683            TbfHeader::Padding(base) => base.header_size,
684        }
685    }
686
687    pub fn is_app(&self) -> bool {
689        match *self {
690            TbfHeader::TbfHeaderV2(_) => true,
691            TbfHeader::Padding(_) => false,
692        }
693    }
694
695    pub fn enabled(&self) -> bool {
698        match *self {
699            TbfHeader::TbfHeaderV2(hd) => {
700                hd.base.flags & 0x00000001 == 1
702            }
703            TbfHeader::Padding(_) => false,
704        }
705    }
706
707    pub fn get_minimum_app_ram_size(&self) -> u32 {
711        match *self {
712            TbfHeader::TbfHeaderV2(hd) => {
713                if hd.program.is_some() {
714                    hd.program.map_or(0, |p| p.minimum_ram_size)
715                } else if hd.main.is_some() {
716                    hd.main.map_or(0, |m| m.minimum_ram_size)
717                } else {
718                    0
719                }
720            }
721            _ => 0,
722        }
723    }
724
725    pub fn get_protected_size(&self) -> u32 {
728        match *self {
729            TbfHeader::TbfHeaderV2(hd) => {
730                if hd.program.is_some() {
731                    hd.program.map_or(0, |p| {
732                        (hd.base.header_size as u32) + p.protected_trailer_size
733                    })
734                } else if hd.main.is_some() {
735                    hd.main.map_or(0, |m| {
736                        (hd.base.header_size as u32) + m.protected_trailer_size
737                    })
738                } else {
739                    0
740                }
741            }
742            _ => 0,
743        }
744    }
745
746    pub fn get_app_start_offset(&self) -> u32 {
750        self.get_protected_size()
753    }
754
755    pub fn get_init_function_offset(&self) -> u32 {
758        match *self {
759            TbfHeader::TbfHeaderV2(hd) => {
760                if hd.program.is_some() {
761                    hd.program
762                        .map_or(0, |p| p.init_fn_offset + (hd.base.header_size as u32))
763                } else if hd.main.is_some() {
764                    hd.main
765                        .map_or(0, |m| m.init_fn_offset + (hd.base.header_size as u32))
766                } else {
767                    0
768                }
769            }
770            _ => 0,
771        }
772    }
773
774    pub fn get_package_name(&self) -> Option<&'a str> {
776        match *self {
777            TbfHeader::TbfHeaderV2(hd) => hd.package_name,
778            _ => None,
779        }
780    }
781
782    pub fn number_writeable_flash_regions(&self) -> usize {
784        match *self {
785            TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or(0, |wr_slice| {
786                let wfr_len = size_of::<TbfHeaderV2WriteableFlashRegion>();
787                wr_slice.len() / wfr_len
788            }),
789            _ => 0,
790        }
791    }
792
793    pub fn get_writeable_flash_region(&self, index: usize) -> (usize, usize) {
795        match *self {
796            TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or((0, 0), |wr_slice| {
797                fn get_region(
798                    wr_slice: &[u8],
799                    index: usize,
800                ) -> Result<TbfHeaderV2WriteableFlashRegion, ()> {
801                    let wfr_len = size_of::<TbfHeaderV2WriteableFlashRegion>();
802
803                    let wfr = wr_slice
804                        .get(index * wfr_len..(index + 1) * wfr_len)
805                        .ok_or(())?
806                        .try_into()
807                        .or(Err(()))?;
808                    Ok(wfr)
809                }
810
811                match get_region(wr_slice, index) {
812                    Ok(wr) => (
813                        wr.writeable_flash_region_offset as usize,
814                        wr.writeable_flash_region_size as usize,
815                    ),
816                    Err(()) => (0, 0),
817                }
818            }),
819            _ => (0, 0),
820        }
821    }
822
823    pub fn get_fixed_address_ram(&self) -> Option<u32> {
826        let hd = match self {
827            TbfHeader::TbfHeaderV2(hd) => hd,
828            _ => return None,
829        };
830        let fixed_addresses: TbfHeaderV2FixedAddresses = hd.fixed_addresses?.try_into().ok()?;
831        match fixed_addresses.start_process_ram {
832            0xFFFFFFFF => None,
833            start => Some(start),
834        }
835    }
836
837    pub fn get_fixed_address_flash(&self) -> Option<u32> {
840        let hd = match self {
841            TbfHeader::TbfHeaderV2(hd) => hd,
842            _ => return None,
843        };
844        let fixed_addresses: TbfHeaderV2FixedAddresses = hd.fixed_addresses?.try_into().ok()?;
845        match fixed_addresses.start_process_flash {
846            0xFFFFFFFF => None,
847            start => Some(start),
848        }
849    }
850
851    pub fn get_command_permissions(&self, driver_num: usize, offset: usize) -> CommandPermissions {
864        match self {
865            TbfHeader::TbfHeaderV2(hd) => match hd.permissions {
866                Some(permissions_tlv_slice) => {
867                    fn get_command_permissions_result(
869                        permissions_tlv_slice: &[u8],
870                        driver_num: usize,
871                        offset: usize,
872                    ) -> Result<CommandPermissions, ()> {
873                        let mut found_driver_num: bool = false;
874                        let perm_len = size_of::<TbfHeaderDriverPermission>();
875
876                        let number_perms = u16::from_le_bytes(
878                            permissions_tlv_slice
879                                .get(0..2)
880                                .ok_or(())?
881                                .try_into()
882                                .or(Err(()))?,
883                        );
884                        let permissions_slice = permissions_tlv_slice.get(2..).ok_or(())?;
886
887                        for i in 0..number_perms as usize {
889                            let perm: TbfHeaderDriverPermission = permissions_slice
890                                .get((i * perm_len)..((i + 1) * perm_len))
891                                .ok_or(())?
892                                .try_into()
893                                .or(Err(()))?;
894
895                            if perm.driver_number == driver_num as u32 {
896                                found_driver_num = true;
897                                if perm.offset == offset as u32 {
898                                    return Ok(CommandPermissions::Mask(perm.allowed_commands));
899                                }
900                            }
901                        }
902
903                        if found_driver_num {
904                            Ok(CommandPermissions::Mask(0))
908                        } else {
909                            Ok(CommandPermissions::NoPermsThisDriver)
910                        }
911                    }
912
913                    get_command_permissions_result(permissions_tlv_slice, driver_num, offset)
914                        .unwrap_or(CommandPermissions::NoPermsAtAll)
915                }
916                _ => CommandPermissions::NoPermsAtAll,
917            },
918            _ => CommandPermissions::NoPermsAtAll,
919        }
920    }
921
922    pub fn get_storage_write_id(&self) -> Option<core::num::NonZeroU32> {
927        match self {
928            TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions {
929                Some(storage_permissions_tlv_slice) => {
930                    let write_id = core::num::NonZeroU32::new(u32::from_le_bytes(
931                        storage_permissions_tlv_slice.get(0..4)?.try_into().ok()?,
932                    ));
933
934                    write_id
935                }
936                _ => None,
937            },
938            _ => None,
939        }
940    }
941
942    pub fn get_storage_read_ids(&self) -> Option<(usize, [u32; NUM_STORAGE_PERMISSIONS])> {
945        match self {
946            TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions {
947                Some(storage_permissions_tlv_slice) => {
948                    let storage_permissions: TbfHeaderV2StoragePermissions<
949                        NUM_STORAGE_PERMISSIONS,
950                    > = storage_permissions_tlv_slice.try_into().ok()?;
951
952                    Some((
953                        storage_permissions.read_length.into(),
954                        storage_permissions.read_ids,
955                    ))
956                }
957                _ => None,
958            },
959            _ => None,
960        }
961    }
962
963    pub fn get_storage_modify_ids(&self) -> Option<(usize, [u32; NUM_STORAGE_PERMISSIONS])> {
966        match self {
967            TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions {
968                Some(storage_permissions_tlv_slice) => {
969                    let storage_permissions: TbfHeaderV2StoragePermissions<
970                        NUM_STORAGE_PERMISSIONS,
971                    > = storage_permissions_tlv_slice.try_into().ok()?;
972
973                    Some((
974                        storage_permissions.modify_length.into(),
975                        storage_permissions.modify_ids,
976                    ))
977                }
978                _ => None,
979            },
980            _ => None,
981        }
982    }
983
984    pub fn get_kernel_version(&self) -> Option<(u16, u16)> {
987        match self {
988            TbfHeader::TbfHeaderV2(hd) => match hd.kernel_version {
989                Some(kernel_version) => Some((kernel_version.major, kernel_version.minor)),
990                _ => None,
991            },
992            _ => None,
993        }
994    }
995
996    pub fn get_binary_end(&self) -> u32 {
1000        match self {
1001            TbfHeader::TbfHeaderV2(hd) => hd
1002                .program
1003                .map_or(hd.base.total_size, |p| p.binary_end_offset),
1004            _ => 0,
1005        }
1006    }
1007
1008    pub fn get_binary_version(&self) -> u32 {
1011        match self {
1012            TbfHeader::TbfHeaderV2(hd) => hd.program.map_or(0, |p| p.version),
1013            _ => 0,
1014        }
1015    }
1016
1017    pub fn get_fixed_short_id(&self) -> Option<core::num::NonZeroU32> {
1020        match self {
1021            TbfHeader::TbfHeaderV2(hd) => hd.short_id.and_then(|si| si.short_id),
1022            _ => None,
1023        }
1024    }
1025}