diff --git a/tbf-parser/src/lib.rs b/tbf-parser/src/lib.rs index 5c01366..6eaa08c 100644 --- a/tbf-parser/src/lib.rs +++ b/tbf-parser/src/lib.rs @@ -1,9 +1,6 @@ -// Adapted from tock-tbf (https://github.com/tock/tock) -// === ORIGINAL LICENSE === // Licensed under the Apache License, Version 2.0 or the MIT License. // SPDX-License-Identifier: Apache-2.0 OR MIT // Copyright Tock Contributors 2022. -// ======================== //! Tock Binary Format (TBF) header parsing library. diff --git a/tbf-parser/src/parse.rs b/tbf-parser/src/parse.rs index e367603..a20a53f 100644 --- a/tbf-parser/src/parse.rs +++ b/tbf-parser/src/parse.rs @@ -1,25 +1,13 @@ -// Adapted from tock-tbf (https://github.com/tock/tock) -// === ORIGINAL LICENSE === // Licensed under the Apache License, Version 2.0 or the MIT License. // SPDX-License-Identifier: Apache-2.0 OR MIT // Copyright Tock Contributors 2022. -// ======================== //! Tock Binary Format parsing code. -use core::convert::TryInto; -use core::iter::Iterator; -use core::mem; +use core::{mem, str}; use crate::types; -/// Takes a value and rounds it up to be aligned % 4 -macro_rules! align4 { - ($e:expr $(,)?) => { - ($e) + ((4 - (($e) % 4)) % 4) - }; -} - /// Parse the TBF header length and the entire length of the TBF binary. /// /// ## Return @@ -81,7 +69,7 @@ pub fn parse_tbf_header_lengths( /// should use the `parse_tbf_header_lengths()` function to determine this /// length to create the correct sized slice. pub fn parse_tbf_header( - header: &[u8], + header: &'static [u8], version: u16, ) -> Result { match version { @@ -124,7 +112,7 @@ pub fn parse_tbf_header( // If there is nothing left in the header then this is just a // padding "app" between two other apps. - if remaining.is_empty() { + if remaining.len() == 0 { // Just padding. Ok(types::TbfHeader::Padding(tbf_header_base)) } else { @@ -134,18 +122,16 @@ pub fn parse_tbf_header( // options. let mut main_pointer: Option = None; let mut program_pointer: Option = None; - let mut wfr_pointer: [Option; 4] = - Default::default(); - let mut package_name_pointer: Option> = None; - let mut fixed_address_pointer: Option = None; - let mut permissions_pointer: Option> = None; - let mut storage_permissions_pointer: Option< - types::TbfHeaderV2StoragePermissions<8>, - > = None; + let mut wfr_pointer: Option<&'static [u8]> = None; + let mut app_name_str = ""; + let mut fixed_address_pointer: Option<&'static [u8]> = None; + let mut permissions_pointer: Option<&'static [u8]> = None; + let mut storage_permissions_pointer: Option<&'static [u8]> = None; let mut kernel_version: Option = None; + let mut short_id: Option = None; // Iterate the remainder of the header looking for TLV entries. - while !remaining.is_empty() { + while remaining.len() > 0 { // Get the T and L portions of the next header (if it is // there). let tlv_header: types::TbfTlv = remaining @@ -199,34 +185,12 @@ pub fn parse_tbf_header( % mem::size_of::() == 0 { - // Calculate how many writeable flash regions - // there are specified in this header. - let wfr_len = - mem::size_of::(); - let mut number_regions = tlv_header.length as usize / wfr_len; - // Capture a slice with just the wfr information. let wfr_slice = remaining .get(0..tlv_header.length as usize) .ok_or(types::TbfParseError::NotEnoughFlash)?; - // To enable a static buffer, we only support up - // to four writeable flash regions. - if number_regions > 4 { - number_regions = 4; - } - - // Convert and store each wfr. - for (i, region) in - wfr_pointer.iter_mut().enumerate().take(number_regions) - { - *region = Some( - wfr_slice - .get(i * wfr_len..(i + 1) * wfr_len) - .ok_or(types::TbfParseError::NotEnoughFlash)? - .try_into()?, - ); - } + wfr_pointer = Some(wfr_slice); } else { return Err(types::TbfParseError::BadTlvEntry( tlv_header.tipe as usize, @@ -239,7 +203,11 @@ pub fn parse_tbf_header( .get(0..tlv_header.length as usize) .ok_or(types::TbfParseError::NotEnoughFlash)?; - package_name_pointer = Some(name_buf.try_into()?); + str::from_utf8(name_buf) + .map(|name_str| { + app_name_str = name_str; + }) + .or(Err(types::TbfParseError::BadProcessName))?; } types::TbfHeaderTypes::TbfHeaderFixedAddresses => { @@ -248,8 +216,7 @@ pub fn parse_tbf_header( fixed_address_pointer = Some( remaining .get(0..entry_len) - .ok_or(types::TbfParseError::NotEnoughFlash)? - .try_into()?, + .ok_or(types::TbfParseError::NotEnoughFlash)?, ); } else { return Err(types::TbfParseError::BadTlvEntry( @@ -259,11 +226,19 @@ pub fn parse_tbf_header( } types::TbfHeaderTypes::TbfHeaderPermissions => { - permissions_pointer = Some(remaining.try_into()?); + permissions_pointer = Some( + remaining + .get(0..tlv_header.length as usize) + .ok_or(types::TbfParseError::NotEnoughFlash)?, + ); } types::TbfHeaderTypes::TbfHeaderStoragePermissions => { - storage_permissions_pointer = Some(remaining.try_into()?); + storage_permissions_pointer = Some( + remaining + .get(0..tlv_header.length as usize) + .ok_or(types::TbfParseError::NotEnoughFlash)?, + ); } types::TbfHeaderTypes::TbfHeaderKernelVersion => { @@ -282,12 +257,30 @@ pub fn parse_tbf_header( } } + types::TbfHeaderTypes::TbfHeaderShortId => { + let entry_len = mem::size_of::(); + if tlv_header.length as usize == entry_len { + short_id = Some( + remaining + .get(0..entry_len) + .ok_or(types::TbfParseError::NotEnoughFlash)? + .try_into()?, + ); + } else { + return Err(types::TbfParseError::BadTlvEntry( + tlv_header.tipe as usize, + )); + } + } + _ => {} } // All TLV blocks are padded to 4 bytes, so we need to skip // more if the length is not a multiple of 4. - let skip_len: usize = align4!(tlv_header.length as usize); + let skip_len: usize = (tlv_header.length as usize) + .checked_next_multiple_of(4) + .ok_or(types::TbfParseError::InternalError)?; remaining = remaining .get(skip_len..) .ok_or(types::TbfParseError::NotEnoughFlash)?; @@ -297,12 +290,13 @@ pub fn parse_tbf_header( base: tbf_header_base, main: main_pointer, program: program_pointer, - package_name: package_name_pointer, - writeable_regions: Some(wfr_pointer), + package_name: Some(app_name_str), + writeable_regions: wfr_pointer, fixed_addresses: fixed_address_pointer, permissions: permissions_pointer, storage_permissions: storage_permissions_pointer, kernel_version, + short_id, }; Ok(types::TbfHeader::TbfHeaderV2(tbf_header)) @@ -313,10 +307,13 @@ pub fn parse_tbf_header( } pub fn parse_tbf_footer( - footers: &[u8], + footers: &'static [u8], ) -> Result<(types::TbfFooterV2Credentials, u32), types::TbfParseError> { let mut remaining = footers; - let tlv_header: types::TbfTlv = remaining.try_into()?; + let tlv_header: types::TbfTlv = remaining + .get(0..4) + .ok_or(types::TbfParseError::NotEnoughFlash)? + .try_into()?; remaining = remaining .get(4..) .ok_or(types::TbfParseError::NotEnoughFlash)?; diff --git a/tbf-parser/src/types.rs b/tbf-parser/src/types.rs index 9f40f19..c12ac77 100644 --- a/tbf-parser/src/types.rs +++ b/tbf-parser/src/types.rs @@ -1,15 +1,11 @@ -// Adapted from tock-tbf (https://github.com/tock/tock) -// === ORIGINAL LICENSE === // Licensed under the Apache License, Version 2.0 or the MIT License. // SPDX-License-Identifier: Apache-2.0 OR MIT // Copyright Tock Contributors 2022. -// ======================== //! Types and Data Structures for TBFs. -use core::convert::TryInto; +use core::fmt; use core::mem::size_of; -use core::{fmt, str}; /// We only support up to a fixed number of storage permissions for each of read /// and modify. This simplification enables us to use fixed sized buffers. @@ -74,10 +70,6 @@ pub enum TbfParseError { /// too long for Tock to parse. /// This can be fixed by increasing the number in `TbfHeaderV2`. TooManyEntries(usize), - - /// The package name is too long for Tock to parse. - /// Consider a shorter name, or increasing the maximum size. - PackageNameTooLong, } impl From for TbfParseError { @@ -111,7 +103,6 @@ impl fmt::Debug for TbfParseError { tipe ) } - TbfParseError::PackageNameTooLong => write!(f, "The package name is too long."), } } } @@ -139,6 +130,7 @@ pub enum TbfHeaderTypes { TbfHeaderStoragePermissions = 7, TbfHeaderKernelVersion = 8, TbfHeaderProgram = 9, + TbfHeaderShortId = 10, TbfFooterCredentials = 128, /// Some field in the header that we do not understand. Since the TLV format @@ -186,12 +178,6 @@ pub struct TbfHeaderV2Program { version: u32, } -#[derive(Clone, Copy, Debug)] -pub struct TbfHeaderV2PackageName { - size: u32, - buffer: [u8; L], -} - /// Writeable flash regions only need an offset and size. /// /// There can be multiple (or zero) flash regions defined, so this is its own @@ -256,6 +242,14 @@ pub struct TbfHeaderV2KernelVersion { minor: u16, } +/// The v2 ShortId for apps. +/// +/// Header to specify a fixed ShortID for an app. +#[derive(Clone, Copy, Debug)] +pub struct TbfHeaderV2ShortId { + short_id: Option, +} + #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum TbfFooterV2CredentialsType { Reserved = 0, @@ -266,59 +260,19 @@ pub enum TbfFooterV2CredentialsType { SHA512 = 5, } -/// Reference: https://github.com/tock/tock/blob/master/doc/reference/trd-appid.md#52-credentials-footer -#[derive(Clone, Copy, Debug)] -#[allow(clippy::large_enum_variant)] -pub enum TbfFooterV2Credentials { - Reserved(u32), - Rsa3072Key(TbfFooterV2RSA<384>), - Rsa4096Key(TbfFooterV2RSA<512>), - SHA256(TbfFooterV2SHA<32>), - SHA384(TbfFooterV2SHA<48>), - SHA512(TbfFooterV2SHA<64>), -} - -#[derive(Clone, Copy, Debug)] -pub struct TbfFooterV2SHA { - hash: [u8; L], -} - #[derive(Clone, Copy, Debug)] -pub struct TbfFooterV2RSA { - public_key: [u8; L], - signature: [u8; L], +pub struct TbfFooterV2Credentials { + format: TbfFooterV2CredentialsType, + data: &'static [u8], } -impl TbfFooterV2SHA { - pub fn get_format(&self) -> Result { - match L { - 32 => Ok(TbfFooterV2CredentialsType::SHA256), - 48 => Ok(TbfFooterV2CredentialsType::SHA384), - 64 => Ok(TbfFooterV2CredentialsType::SHA512), - _ => Err(TbfParseError::InternalError), - } +impl TbfFooterV2Credentials { + pub fn format(&self) -> TbfFooterV2CredentialsType { + self.format } - pub fn get_hash(&self) -> &[u8; L] { - &self.hash - } -} - -impl TbfFooterV2RSA { - pub fn get_format(&self) -> Result { - match L { - 384 => Ok(TbfFooterV2CredentialsType::Rsa3072Key), - 512 => Ok(TbfFooterV2CredentialsType::Rsa4096Key), - _ => Err(TbfParseError::InternalError), - } - } - - pub fn get_public_key(&self) -> &[u8; L] { - &self.public_key - } - - pub fn get_signature(&self) -> &[u8; L] { - &self.signature + pub fn data(&self) -> &'static [u8] { + self.data } } @@ -374,6 +328,7 @@ impl core::convert::TryFrom for TbfHeaderTypes { 7 => Ok(TbfHeaderTypes::TbfHeaderStoragePermissions), 8 => Ok(TbfHeaderTypes::TbfHeaderKernelVersion), 9 => Ok(TbfHeaderTypes::TbfHeaderProgram), + 10 => Ok(TbfHeaderTypes::TbfHeaderShortId), 128 => Ok(TbfHeaderTypes::TbfFooterCredentials), _ => Ok(TbfHeaderTypes::Unknown), } @@ -465,28 +420,6 @@ impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Program { } } -impl core::convert::TryFrom<&[u8]> for TbfHeaderV2PackageName { - type Error = TbfParseError; - - fn try_from(value: &[u8]) -> Result { - if value.len() > L { - return Err(TbfParseError::PackageNameTooLong); - } - - if str::from_utf8(value).is_err() { - return Err(TbfParseError::BadProcessName); - } - - let mut buffer = [0u8; L]; - buffer[..value.len()].copy_from_slice(value); - - Ok(TbfHeaderV2PackageName { - size: value.len() as u32, - buffer, - }) - } -} - impl core::convert::TryFrom<&[u8]> for TbfHeaderV2WriteableFlashRegion { type Error = TbfParseError; @@ -553,43 +486,6 @@ impl core::convert::TryFrom<&[u8]> for TbfHeaderDriverPermission { } } -impl core::convert::TryFrom<&[u8]> for TbfHeaderV2Permissions { - type Error = TbfParseError; - - fn try_from(b: &[u8]) -> Result, Self::Error> { - let number_perms = u16::from_le_bytes( - b.get(0..2) - .ok_or(TbfParseError::NotEnoughFlash)? - .try_into()?, - ); - - let mut perms: [TbfHeaderDriverPermission; L] = [TbfHeaderDriverPermission { - driver_number: 0, - offset: 0, - allowed_commands: 0, - }; L]; - for i in 0..number_perms as usize { - let start = 2 + (i * size_of::()); - let end = start + size_of::(); - if let Some(perm) = perms.get_mut(i) { - *perm = b - .get(start..end) - .ok_or(TbfParseError::NotEnoughFlash)? - .try_into()?; - } else { - return Err(TbfParseError::BadTlvEntry( - TbfHeaderTypes::TbfHeaderPermissions as usize, - )); - } - } - - Ok(TbfHeaderV2Permissions { - length: number_perms, - perms, - }) - } -} - impl core::convert::TryFrom<&[u8]> for TbfHeaderV2StoragePermissions { type Error = TbfParseError; @@ -677,11 +573,25 @@ impl core::convert::TryFrom<&[u8]> for TbfHeaderV2KernelVersion { } } -impl core::convert::TryFrom<&[u8]> for TbfFooterV2Credentials { +impl core::convert::TryFrom<&[u8]> for TbfHeaderV2ShortId { + type Error = TbfParseError; + + fn try_from(b: &[u8]) -> Result { + Ok(TbfHeaderV2ShortId { + short_id: core::num::NonZeroU32::new(u32::from_le_bytes( + b.get(0..4) + .ok_or(TbfParseError::InternalError)? + .try_into()?, + )), + }) + } +} + +impl core::convert::TryFrom<&'static [u8]> for TbfFooterV2Credentials { type Error = TbfParseError; - fn try_from(b: &[u8]) -> Result { - let format: u32 = u32::from_le_bytes( + fn try_from(b: &'static [u8]) -> Result { + let format = u32::from_le_bytes( b.get(0..4) .ok_or(TbfParseError::InternalError)? .try_into()?, @@ -694,7 +604,9 @@ impl core::convert::TryFrom<&[u8]> for TbfFooterV2Credentials { 4 => TbfFooterV2CredentialsType::SHA384, 5 => TbfFooterV2CredentialsType::SHA512, _ => { - return Err(TbfParseError::InternalError); + return Err(TbfParseError::BadTlvEntry( + TbfHeaderTypes::TbfFooterCredentials as usize, + )); } }; let length = match ftype { @@ -705,51 +617,13 @@ impl core::convert::TryFrom<&[u8]> for TbfFooterV2Credentials { TbfFooterV2CredentialsType::SHA384 => 48, TbfFooterV2CredentialsType::SHA512 => 64, }; - - let data = b + let data = &b .get(4..(length + 4)) .ok_or(TbfParseError::NotEnoughFlash)?; - - match ftype { - TbfFooterV2CredentialsType::Reserved => { - Ok(TbfFooterV2Credentials::Reserved(b.len() as u32)) - } - TbfFooterV2CredentialsType::SHA256 => { - Ok(TbfFooterV2Credentials::SHA256(TbfFooterV2SHA { - hash: data.try_into().map_err(|_| TbfParseError::InternalError)?, - })) - } - TbfFooterV2CredentialsType::SHA384 => { - Ok(TbfFooterV2Credentials::SHA384(TbfFooterV2SHA { - hash: data.try_into().map_err(|_| TbfParseError::InternalError)?, - })) - } - TbfFooterV2CredentialsType::SHA512 => { - Ok(TbfFooterV2Credentials::SHA512(TbfFooterV2SHA { - hash: data.try_into().map_err(|_| TbfParseError::InternalError)?, - })) - } - TbfFooterV2CredentialsType::Rsa3072Key => { - Ok(TbfFooterV2Credentials::Rsa3072Key(TbfFooterV2RSA { - public_key: data[0..length / 2] - .try_into() - .map_err(|_| TbfParseError::InternalError)?, - signature: data[length / 2..] - .try_into() - .map_err(|_| TbfParseError::InternalError)?, - })) - } - TbfFooterV2CredentialsType::Rsa4096Key => { - Ok(TbfFooterV2Credentials::Rsa4096Key(TbfFooterV2RSA { - public_key: data[0..length / 2] - .try_into() - .map_err(|_| TbfParseError::InternalError)?, - signature: data[length / 2..] - .try_into() - .map_err(|_| TbfParseError::InternalError)?, - })) - } - } + Ok(TbfFooterV2Credentials { + format: ftype, + data, + }) } } @@ -777,12 +651,13 @@ pub struct TbfHeaderV2 { pub(crate) base: TbfHeaderV2Base, pub(crate) main: Option, pub(crate) program: Option, - pub(crate) package_name: Option>, - pub(crate) writeable_regions: Option<[Option; 4]>, - pub(crate) fixed_addresses: Option, - pub(crate) permissions: Option>, - pub(crate) storage_permissions: Option>, + pub(crate) package_name: Option<&'static str>, + pub(crate) writeable_regions: Option<&'static [u8]>, + pub(crate) fixed_addresses: Option<&'static [u8]>, + pub(crate) permissions: Option<&'static [u8]>, + pub(crate) storage_permissions: Option<&'static [u8]>, pub(crate) kernel_version: Option, + pub(crate) short_id: Option, } /// Type that represents the fields of the Tock Binary Format header. @@ -792,9 +667,6 @@ pub struct TbfHeaderV2 { /// The kernel can also use this header to keep persistent state about /// the application. #[derive(Debug)] -// Clippy suggests we box TbfHeaderV2. We can't really do that, since -// we are runnning under no_std, and I don't think it's that big of a issue. -#[allow(clippy::large_enum_variant)] pub enum TbfHeader { TbfHeaderV2(TbfHeaderV2), Padding(TbfHeaderV2Base), @@ -897,13 +769,9 @@ impl TbfHeader { } /// Get the name of the app. - // Note: We could return Result instead. So far, no editing methods have been implemented, and when the PackageName struct is created - // the str::from_utf8 function is ran beforehand to make sure the bytes are valid UTF-8. - pub fn get_package_name(&self) -> Option<&str> { - match self { - TbfHeader::TbfHeaderV2(hd) => hd.package_name.as_ref().map(|name| { - str::from_utf8(&name.buffer[..name.size as usize]).expect("Package name is not valid UTF8. Conversion should have been checked beforehand.") - }), + pub fn get_package_name(&self) -> Option<&'static str> { + match *self { + TbfHeader::TbfHeaderV2(hd) => hd.package_name, _ => None, } } @@ -911,9 +779,9 @@ impl TbfHeader { /// Get the number of flash regions this app has specified in its header. pub fn number_writeable_flash_regions(&self) -> usize { match *self { - TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or(0, |wrs| { - wrs.iter() - .fold(0, |acc, wr| if wr.is_some() { acc + 1 } else { acc }) + TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or(0, |wr_slice| { + let wfr_len = size_of::(); + wr_slice.len() / wfr_len }), _ => 0, } @@ -922,13 +790,28 @@ impl TbfHeader { /// Get the offset and size of a given flash region. pub fn get_writeable_flash_region(&self, index: usize) -> (u32, u32) { match *self { - TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or((0, 0), |wrs| { - wrs.get(index).unwrap_or(&None).map_or((0, 0), |wr| { - ( + TbfHeader::TbfHeaderV2(hd) => hd.writeable_regions.map_or((0, 0), |wr_slice| { + fn get_region( + wr_slice: &'static [u8], + index: usize, + ) -> Result { + let wfr_len = size_of::(); + + let wfr = wr_slice + .get(index * wfr_len..(index + 1) * wfr_len) + .ok_or(())? + .try_into() + .or(Err(()))?; + Ok(wfr) + } + + match get_region(wr_slice, index) { + Ok(wr) => ( wr.writeable_flash_region_offset, wr.writeable_flash_region_size, - ) - }) + ), + Err(()) => (0, 0), + } }), _ => (0, 0), } @@ -941,7 +824,8 @@ impl TbfHeader { TbfHeader::TbfHeaderV2(hd) => hd, _ => return None, }; - match hd.fixed_addresses.as_ref()?.start_process_ram { + let fixed_addresses: TbfHeaderV2FixedAddresses = hd.fixed_addresses?.try_into().ok()?; + match fixed_addresses.start_process_ram { 0xFFFFFFFF => None, start => Some(start), } @@ -954,7 +838,8 @@ impl TbfHeader { TbfHeader::TbfHeaderV2(hd) => hd, _ => return None, }; - match hd.fixed_addresses.as_ref()?.start_process_flash { + let fixed_addresses: TbfHeaderV2FixedAddresses = hd.fixed_addresses?.try_into().ok()?; + match fixed_addresses.start_process_flash { 0xFFFFFFFF => None, start => Some(start), } @@ -975,24 +860,55 @@ impl TbfHeader { pub fn get_command_permissions(&self, driver_num: usize, offset: usize) -> CommandPermissions { match self { TbfHeader::TbfHeaderV2(hd) => match hd.permissions { - Some(permissions) => { - let mut found_driver_num: bool = false; - for perm in permissions.perms { - if perm.driver_number == driver_num as u32 { - found_driver_num = true; - if perm.offset == offset as u32 { - return CommandPermissions::Mask(perm.allowed_commands); + Some(permissions_tlv_slice) => { + // Helper function to wrap the return in a Result. + fn get_command_permissions_result( + permissions_tlv_slice: &'static [u8], + driver_num: usize, + offset: usize, + ) -> Result { + let mut found_driver_num: bool = false; + let perm_len = size_of::(); + + // Read the number of stored permissions. + let number_perms = u16::from_le_bytes( + permissions_tlv_slice + .get(0..2) + .ok_or(())? + .try_into() + .or(Err(()))?, + ); + // Get the remaining slice of just the permissions. + let permissions_slice = permissions_tlv_slice.get(2..).ok_or(())?; + + // Iterate the permissions to find a match. + for i in 0..number_perms as usize { + let perm: TbfHeaderDriverPermission = permissions_slice + .get((i * perm_len)..((i + 1) * perm_len)) + .ok_or(())? + .try_into() + .or(Err(()))?; + + if perm.driver_number == driver_num as u32 { + found_driver_num = true; + if perm.offset == offset as u32 { + return Ok(CommandPermissions::Mask(perm.allowed_commands)); + } } } + + if found_driver_num { + // We found this driver number but nothing matched the + // requested offset. Since permissions are default off, + // we can return a mask of all zeros. + Ok(CommandPermissions::Mask(0)) + } else { + Ok(CommandPermissions::NoPermsThisDriver) + } } - if found_driver_num { - // We found this driver number but nothing matched the - // requested offset. Since permissions are default off, - // we can return a mask of all zeros. - CommandPermissions::Mask(0) - } else { - CommandPermissions::NoPermsThisDriver - } + + get_command_permissions_result(permissions_tlv_slice, driver_num, offset) + .unwrap_or(CommandPermissions::NoPermsAtAll) } _ => CommandPermissions::NoPermsAtAll, }, @@ -1007,7 +923,13 @@ impl TbfHeader { pub fn get_storage_write_id(&self) -> Option { match self { TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions { - Some(permissions) => permissions.write_id, + Some(storage_permissions_tlv_slice) => { + let write_id = core::num::NonZeroU32::new(u32::from_le_bytes( + storage_permissions_tlv_slice.get(0..4)?.try_into().ok()?, + )); + + write_id + } _ => None, }, _ => None, @@ -1018,9 +940,19 @@ impl TbfHeader { /// Returns `None` if a `read_ids` is not included. pub fn get_storage_read_ids(&self) -> Option<(usize, [u32; NUM_STORAGE_PERMISSIONS])> { match self { - TbfHeader::TbfHeaderV2(hd) => hd - .storage_permissions - .map(|permissions| (permissions.read_length.into(), permissions.read_ids)), + TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions { + Some(storage_permissions_tlv_slice) => { + let storage_permissions: TbfHeaderV2StoragePermissions< + NUM_STORAGE_PERMISSIONS, + > = storage_permissions_tlv_slice.try_into().ok()?; + + Some(( + storage_permissions.read_length.into(), + storage_permissions.read_ids, + )) + } + _ => None, + }, _ => None, } } @@ -1029,9 +961,19 @@ impl TbfHeader { /// Returns `None` if a `access_ids` is not included. pub fn get_storage_modify_ids(&self) -> Option<(usize, [u32; NUM_STORAGE_PERMISSIONS])> { match self { - TbfHeader::TbfHeaderV2(hd) => hd - .storage_permissions - .map(|permissions| (permissions.modify_length.into(), permissions.modify_ids)), + TbfHeader::TbfHeaderV2(hd) => match hd.storage_permissions { + Some(storage_permissions_tlv_slice) => { + let storage_permissions: TbfHeaderV2StoragePermissions< + NUM_STORAGE_PERMISSIONS, + > = storage_permissions_tlv_slice.try_into().ok()?; + + Some(( + storage_permissions.modify_length.into(), + storage_permissions.modify_ids, + )) + } + _ => None, + }, _ => None, } } @@ -1040,9 +982,10 @@ impl TbfHeader { /// Returns `None` if the kernel compatibility header is not included. pub fn get_kernel_version(&self) -> Option<(u16, u16)> { match self { - TbfHeader::TbfHeaderV2(hd) => hd - .kernel_version - .map(|kernel_version| (kernel_version.major, kernel_version.minor)), + TbfHeader::TbfHeaderV2(hd) => match hd.kernel_version { + Some(kernel_version) => Some((kernel_version.major, kernel_version.minor)), + _ => None, + }, _ => None, } } @@ -1067,4 +1010,13 @@ impl TbfHeader { _ => 0, } } + + /// Return the fixed ShortId of the application if it was specified in the + /// TBF header. + pub fn get_fixed_short_id(&self) -> Option { + match self { + TbfHeader::TbfHeaderV2(hd) => hd.short_id.map_or(None, |si| si.short_id), + _ => None, + } + } }