1*d289c2baSAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project 2*d289c2baSAndroid Build Coastguard Worker // 3*d289c2baSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*d289c2baSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*d289c2baSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*d289c2baSAndroid Build Coastguard Worker // 7*d289c2baSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0 8*d289c2baSAndroid Build Coastguard Worker // 9*d289c2baSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*d289c2baSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*d289c2baSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*d289c2baSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*d289c2baSAndroid Build Coastguard Worker // limitations under the License. 14*d289c2baSAndroid Build Coastguard Worker 15*d289c2baSAndroid Build Coastguard Worker //! Hashtree descriptors. 16*d289c2baSAndroid Build Coastguard Worker 17*d289c2baSAndroid Build Coastguard Worker use super::{ 18*d289c2baSAndroid Build Coastguard Worker util::{parse_descriptor, split_slice, ValidateAndByteswap, ValidationFunc}, 19*d289c2baSAndroid Build Coastguard Worker DescriptorResult, 20*d289c2baSAndroid Build Coastguard Worker }; 21*d289c2baSAndroid Build Coastguard Worker use avb_bindgen::{avb_hashtree_descriptor_validate_and_byteswap, AvbHashtreeDescriptor}; 22*d289c2baSAndroid Build Coastguard Worker use core::{ffi::CStr, str::from_utf8}; 23*d289c2baSAndroid Build Coastguard Worker 24*d289c2baSAndroid Build Coastguard Worker /// `AvbHashtreeDescriptorFlags`; see libavb docs for details. 25*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbHashtreeDescriptorFlags as HashtreeDescriptorFlags; 26*d289c2baSAndroid Build Coastguard Worker 27*d289c2baSAndroid Build Coastguard Worker /// Wraps a Hashtree descriptor stored in a vbmeta image. 28*d289c2baSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)] 29*d289c2baSAndroid Build Coastguard Worker pub struct HashtreeDescriptor<'a> { 30*d289c2baSAndroid Build Coastguard Worker /// DM-Verity version. 31*d289c2baSAndroid Build Coastguard Worker pub dm_verity_version: u32, 32*d289c2baSAndroid Build Coastguard Worker 33*d289c2baSAndroid Build Coastguard Worker /// Hashed image size. 34*d289c2baSAndroid Build Coastguard Worker pub image_size: u64, 35*d289c2baSAndroid Build Coastguard Worker 36*d289c2baSAndroid Build Coastguard Worker /// Offset to the root block of the hash tree. 37*d289c2baSAndroid Build Coastguard Worker pub tree_offset: u64, 38*d289c2baSAndroid Build Coastguard Worker 39*d289c2baSAndroid Build Coastguard Worker /// Hash tree size. 40*d289c2baSAndroid Build Coastguard Worker pub tree_size: u64, 41*d289c2baSAndroid Build Coastguard Worker 42*d289c2baSAndroid Build Coastguard Worker /// Data block size in bytes. 43*d289c2baSAndroid Build Coastguard Worker pub data_block_size: u32, 44*d289c2baSAndroid Build Coastguard Worker 45*d289c2baSAndroid Build Coastguard Worker /// Hash block size in bytes. 46*d289c2baSAndroid Build Coastguard Worker pub hash_block_size: u32, 47*d289c2baSAndroid Build Coastguard Worker 48*d289c2baSAndroid Build Coastguard Worker /// Number of forward error correction roots. 49*d289c2baSAndroid Build Coastguard Worker pub fec_num_roots: u32, 50*d289c2baSAndroid Build Coastguard Worker 51*d289c2baSAndroid Build Coastguard Worker /// Offset to the forward error correction data. 52*d289c2baSAndroid Build Coastguard Worker pub fec_offset: u64, 53*d289c2baSAndroid Build Coastguard Worker 54*d289c2baSAndroid Build Coastguard Worker /// Forward error correction data size. 55*d289c2baSAndroid Build Coastguard Worker pub fec_size: u64, 56*d289c2baSAndroid Build Coastguard Worker 57*d289c2baSAndroid Build Coastguard Worker /// Hash algorithm name. 58*d289c2baSAndroid Build Coastguard Worker pub hash_algorithm: &'a str, 59*d289c2baSAndroid Build Coastguard Worker 60*d289c2baSAndroid Build Coastguard Worker /// Flags. 61*d289c2baSAndroid Build Coastguard Worker pub flags: HashtreeDescriptorFlags, 62*d289c2baSAndroid Build Coastguard Worker 63*d289c2baSAndroid Build Coastguard Worker /// Partition name. 64*d289c2baSAndroid Build Coastguard Worker pub partition_name: &'a str, 65*d289c2baSAndroid Build Coastguard Worker 66*d289c2baSAndroid Build Coastguard Worker /// Salt used to hash the image. 67*d289c2baSAndroid Build Coastguard Worker pub salt: &'a [u8], 68*d289c2baSAndroid Build Coastguard Worker 69*d289c2baSAndroid Build Coastguard Worker /// Image root hash digest. 70*d289c2baSAndroid Build Coastguard Worker pub root_digest: &'a [u8], 71*d289c2baSAndroid Build Coastguard Worker } 72*d289c2baSAndroid Build Coastguard Worker 73*d289c2baSAndroid Build Coastguard Worker // SAFETY: `VALIDATE_AND_BYTESWAP_FUNC` is the correct libavb validator for this descriptor type. 74*d289c2baSAndroid Build Coastguard Worker unsafe impl ValidateAndByteswap for AvbHashtreeDescriptor { 75*d289c2baSAndroid Build Coastguard Worker const VALIDATE_AND_BYTESWAP_FUNC: ValidationFunc<Self> = 76*d289c2baSAndroid Build Coastguard Worker avb_hashtree_descriptor_validate_and_byteswap; 77*d289c2baSAndroid Build Coastguard Worker } 78*d289c2baSAndroid Build Coastguard Worker 79*d289c2baSAndroid Build Coastguard Worker impl<'a> HashtreeDescriptor<'a> { 80*d289c2baSAndroid Build Coastguard Worker /// Extract a `HashtreeDescriptor` from the given descriptor contents. 81*d289c2baSAndroid Build Coastguard Worker /// 82*d289c2baSAndroid Build Coastguard Worker /// # Arguments 83*d289c2baSAndroid Build Coastguard Worker /// * `contents`: descriptor contents, including the header, in raw big-endian format. 84*d289c2baSAndroid Build Coastguard Worker /// 85*d289c2baSAndroid Build Coastguard Worker /// # Returns 86*d289c2baSAndroid Build Coastguard Worker /// The new descriptor, or `DescriptorError` if the given `contents` aren't a valid 87*d289c2baSAndroid Build Coastguard Worker /// `AvbHashtreeDescriptor`. new(contents: &'a [u8]) -> DescriptorResult<Self>88*d289c2baSAndroid Build Coastguard Worker pub(super) fn new(contents: &'a [u8]) -> DescriptorResult<Self> { 89*d289c2baSAndroid Build Coastguard Worker // Descriptor contains: header + name + salt + digest. 90*d289c2baSAndroid Build Coastguard Worker let descriptor = parse_descriptor::<AvbHashtreeDescriptor>(contents)?; 91*d289c2baSAndroid Build Coastguard Worker let (partition_name, remainder) = 92*d289c2baSAndroid Build Coastguard Worker split_slice(descriptor.body, descriptor.header.partition_name_len)?; 93*d289c2baSAndroid Build Coastguard Worker let (salt, remainder) = split_slice(remainder, descriptor.header.salt_len)?; 94*d289c2baSAndroid Build Coastguard Worker let (root_digest, _) = split_slice(remainder, descriptor.header.root_digest_len)?; 95*d289c2baSAndroid Build Coastguard Worker 96*d289c2baSAndroid Build Coastguard Worker // Extract the hash algorithm from the original raw header since the temporary 97*d289c2baSAndroid Build Coastguard Worker // byte-swapped header doesn't live past this function. 98*d289c2baSAndroid Build Coastguard Worker // The hash algorithm is a nul-terminated UTF-8 string which is identical in the raw 99*d289c2baSAndroid Build Coastguard Worker // and byteswapped headers. 100*d289c2baSAndroid Build Coastguard Worker let hash_algorithm = 101*d289c2baSAndroid Build Coastguard Worker CStr::from_bytes_until_nul(&descriptor.raw_header.hash_algorithm)?.to_str()?; 102*d289c2baSAndroid Build Coastguard Worker 103*d289c2baSAndroid Build Coastguard Worker Ok(Self { 104*d289c2baSAndroid Build Coastguard Worker dm_verity_version: descriptor.header.dm_verity_version, 105*d289c2baSAndroid Build Coastguard Worker image_size: descriptor.header.image_size, 106*d289c2baSAndroid Build Coastguard Worker tree_offset: descriptor.header.tree_offset, 107*d289c2baSAndroid Build Coastguard Worker tree_size: descriptor.header.tree_size, 108*d289c2baSAndroid Build Coastguard Worker data_block_size: descriptor.header.data_block_size, 109*d289c2baSAndroid Build Coastguard Worker hash_block_size: descriptor.header.hash_block_size, 110*d289c2baSAndroid Build Coastguard Worker fec_num_roots: descriptor.header.fec_num_roots, 111*d289c2baSAndroid Build Coastguard Worker fec_offset: descriptor.header.fec_offset, 112*d289c2baSAndroid Build Coastguard Worker fec_size: descriptor.header.fec_size, 113*d289c2baSAndroid Build Coastguard Worker hash_algorithm, 114*d289c2baSAndroid Build Coastguard Worker partition_name: from_utf8(partition_name)?, 115*d289c2baSAndroid Build Coastguard Worker salt, 116*d289c2baSAndroid Build Coastguard Worker root_digest, 117*d289c2baSAndroid Build Coastguard Worker flags: HashtreeDescriptorFlags(descriptor.header.flags), 118*d289c2baSAndroid Build Coastguard Worker }) 119*d289c2baSAndroid Build Coastguard Worker } 120*d289c2baSAndroid Build Coastguard Worker } 121*d289c2baSAndroid Build Coastguard Worker 122*d289c2baSAndroid Build Coastguard Worker #[cfg(test)] 123*d289c2baSAndroid Build Coastguard Worker mod tests { 124*d289c2baSAndroid Build Coastguard Worker use super::*; 125*d289c2baSAndroid Build Coastguard Worker 126*d289c2baSAndroid Build Coastguard Worker use crate::DescriptorError; 127*d289c2baSAndroid Build Coastguard Worker use std::{fs, mem::size_of}; 128*d289c2baSAndroid Build Coastguard Worker 129*d289c2baSAndroid Build Coastguard Worker /// A valid descriptor that we've pre-generated as test data. test_contents() -> Vec<u8>130*d289c2baSAndroid Build Coastguard Worker fn test_contents() -> Vec<u8> { 131*d289c2baSAndroid Build Coastguard Worker fs::read("testdata/hashtree_descriptor.bin").unwrap() 132*d289c2baSAndroid Build Coastguard Worker } 133*d289c2baSAndroid Build Coastguard Worker 134*d289c2baSAndroid Build Coastguard Worker #[test] new_hashtree_descriptor_success()135*d289c2baSAndroid Build Coastguard Worker fn new_hashtree_descriptor_success() { 136*d289c2baSAndroid Build Coastguard Worker assert!(HashtreeDescriptor::new(&test_contents()).is_ok()); 137*d289c2baSAndroid Build Coastguard Worker } 138*d289c2baSAndroid Build Coastguard Worker 139*d289c2baSAndroid Build Coastguard Worker #[test] new_hashtree_descriptor_too_short_header_fails()140*d289c2baSAndroid Build Coastguard Worker fn new_hashtree_descriptor_too_short_header_fails() { 141*d289c2baSAndroid Build Coastguard Worker let bad_header_size = size_of::<AvbHashtreeDescriptor>() - 1; 142*d289c2baSAndroid Build Coastguard Worker assert_eq!( 143*d289c2baSAndroid Build Coastguard Worker HashtreeDescriptor::new(&test_contents()[..bad_header_size]).unwrap_err(), 144*d289c2baSAndroid Build Coastguard Worker DescriptorError::InvalidHeader 145*d289c2baSAndroid Build Coastguard Worker ); 146*d289c2baSAndroid Build Coastguard Worker } 147*d289c2baSAndroid Build Coastguard Worker 148*d289c2baSAndroid Build Coastguard Worker #[test] new_hashtree_descriptor_too_short_contents_fails()149*d289c2baSAndroid Build Coastguard Worker fn new_hashtree_descriptor_too_short_contents_fails() { 150*d289c2baSAndroid Build Coastguard Worker // The last 2 bytes are padding, so we need to drop 3 bytes to trigger an error. 151*d289c2baSAndroid Build Coastguard Worker let bad_contents_size = test_contents().len() - 3; 152*d289c2baSAndroid Build Coastguard Worker assert_eq!( 153*d289c2baSAndroid Build Coastguard Worker HashtreeDescriptor::new(&test_contents()[..bad_contents_size]).unwrap_err(), 154*d289c2baSAndroid Build Coastguard Worker DescriptorError::InvalidSize 155*d289c2baSAndroid Build Coastguard Worker ); 156*d289c2baSAndroid Build Coastguard Worker } 157*d289c2baSAndroid Build Coastguard Worker } 158