xref: /aosp_15_r20/external/avb/rust/src/descriptor/hashtree.rs (revision d289c2ba6de359471b23d594623b906876bc48a0)
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