xref: /aosp_15_r20/external/avb/rust/src/descriptor/hash.rs (revision d289c2ba6de359471b23d594623b906876bc48a0)
1*d289c2baSAndroid Build Coastguard Worker // Copyright 2023, 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 //! Hash 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_hash_descriptor_validate_and_byteswap, AvbHashDescriptor};
22*d289c2baSAndroid Build Coastguard Worker use core::{ffi::CStr, str::from_utf8};
23*d289c2baSAndroid Build Coastguard Worker 
24*d289c2baSAndroid Build Coastguard Worker /// `AvbHashDescriptorFlags`; see libavb docs for details.
25*d289c2baSAndroid Build Coastguard Worker pub use avb_bindgen::AvbHashDescriptorFlags as HashDescriptorFlags;
26*d289c2baSAndroid Build Coastguard Worker 
27*d289c2baSAndroid Build Coastguard Worker /// Wraps a Hash descriptor stored in a vbmeta image.
28*d289c2baSAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)]
29*d289c2baSAndroid Build Coastguard Worker pub struct HashDescriptor<'a> {
30*d289c2baSAndroid Build Coastguard Worker     /// The size of the hashed image.
31*d289c2baSAndroid Build Coastguard Worker     pub image_size: u64,
32*d289c2baSAndroid Build Coastguard Worker 
33*d289c2baSAndroid Build Coastguard Worker     /// Hash algorithm name.
34*d289c2baSAndroid Build Coastguard Worker     pub hash_algorithm: &'a str,
35*d289c2baSAndroid Build Coastguard Worker 
36*d289c2baSAndroid Build Coastguard Worker     /// Flags.
37*d289c2baSAndroid Build Coastguard Worker     pub flags: HashDescriptorFlags,
38*d289c2baSAndroid Build Coastguard Worker 
39*d289c2baSAndroid Build Coastguard Worker     /// Partition name.
40*d289c2baSAndroid Build Coastguard Worker     ///
41*d289c2baSAndroid Build Coastguard Worker     /// Most partition names in this library are passed as `&CStr`, but inside
42*d289c2baSAndroid Build Coastguard Worker     /// descriptors the partition names are not nul-terminated making them
43*d289c2baSAndroid Build Coastguard Worker     /// ineligible for use directly as `&CStr`. If `&CStr` is required, one
44*d289c2baSAndroid Build Coastguard Worker     /// option is to allocate a nul-terminated copy of this string via
45*d289c2baSAndroid Build Coastguard Worker     /// `CString::new()` which can then be converted to `&CStr`.
46*d289c2baSAndroid Build Coastguard Worker     pub partition_name: &'a str,
47*d289c2baSAndroid Build Coastguard Worker 
48*d289c2baSAndroid Build Coastguard Worker     /// Salt used to hash the image.
49*d289c2baSAndroid Build Coastguard Worker     pub salt: &'a [u8],
50*d289c2baSAndroid Build Coastguard Worker 
51*d289c2baSAndroid Build Coastguard Worker     /// Image hash digest.
52*d289c2baSAndroid Build Coastguard Worker     pub digest: &'a [u8],
53*d289c2baSAndroid Build Coastguard Worker }
54*d289c2baSAndroid Build Coastguard Worker 
55*d289c2baSAndroid Build Coastguard Worker // SAFETY: `VALIDATE_AND_BYTESWAP_FUNC` is the correct libavb validator for this descriptor type.
56*d289c2baSAndroid Build Coastguard Worker unsafe impl ValidateAndByteswap for AvbHashDescriptor {
57*d289c2baSAndroid Build Coastguard Worker     const VALIDATE_AND_BYTESWAP_FUNC: ValidationFunc<Self> =
58*d289c2baSAndroid Build Coastguard Worker         avb_hash_descriptor_validate_and_byteswap;
59*d289c2baSAndroid Build Coastguard Worker }
60*d289c2baSAndroid Build Coastguard Worker 
61*d289c2baSAndroid Build Coastguard Worker impl<'a> HashDescriptor<'a> {
62*d289c2baSAndroid Build Coastguard Worker     /// Extract a `HashDescriptor` from the given descriptor contents.
63*d289c2baSAndroid Build Coastguard Worker     ///
64*d289c2baSAndroid Build Coastguard Worker     /// # Arguments
65*d289c2baSAndroid Build Coastguard Worker     /// * `contents`: descriptor contents, including the header, in raw big-endian format.
66*d289c2baSAndroid Build Coastguard Worker     ///
67*d289c2baSAndroid Build Coastguard Worker     /// # Returns
68*d289c2baSAndroid Build Coastguard Worker     /// The new descriptor, or `DescriptorError` if the given `contents` aren't a valid
69*d289c2baSAndroid Build Coastguard Worker     /// `AvbHashDescriptor`.
new(contents: &'a [u8]) -> DescriptorResult<Self>70*d289c2baSAndroid Build Coastguard Worker     pub(super) fn new(contents: &'a [u8]) -> DescriptorResult<Self> {
71*d289c2baSAndroid Build Coastguard Worker         // Descriptor contains: header + name + salt + digest.
72*d289c2baSAndroid Build Coastguard Worker         let descriptor = parse_descriptor::<AvbHashDescriptor>(contents)?;
73*d289c2baSAndroid Build Coastguard Worker         let (partition_name, remainder) =
74*d289c2baSAndroid Build Coastguard Worker             split_slice(descriptor.body, descriptor.header.partition_name_len)?;
75*d289c2baSAndroid Build Coastguard Worker         let (salt, remainder) = split_slice(remainder, descriptor.header.salt_len)?;
76*d289c2baSAndroid Build Coastguard Worker         let (digest, _) = split_slice(remainder, descriptor.header.digest_len)?;
77*d289c2baSAndroid Build Coastguard Worker 
78*d289c2baSAndroid Build Coastguard Worker         // Extract the hash algorithm from the original raw header since the temporary
79*d289c2baSAndroid Build Coastguard Worker         // byte-swapped header doesn't live past this function.
80*d289c2baSAndroid Build Coastguard Worker         // The hash algorithm is a nul-terminated UTF-8 string which is identical in the raw
81*d289c2baSAndroid Build Coastguard Worker         // and byteswapped headers.
82*d289c2baSAndroid Build Coastguard Worker         let hash_algorithm =
83*d289c2baSAndroid Build Coastguard Worker             CStr::from_bytes_until_nul(&descriptor.raw_header.hash_algorithm)?.to_str()?;
84*d289c2baSAndroid Build Coastguard Worker 
85*d289c2baSAndroid Build Coastguard Worker         Ok(Self {
86*d289c2baSAndroid Build Coastguard Worker             image_size: descriptor.header.image_size,
87*d289c2baSAndroid Build Coastguard Worker             hash_algorithm,
88*d289c2baSAndroid Build Coastguard Worker             flags: HashDescriptorFlags(descriptor.header.flags),
89*d289c2baSAndroid Build Coastguard Worker             partition_name: from_utf8(partition_name)?,
90*d289c2baSAndroid Build Coastguard Worker             salt,
91*d289c2baSAndroid Build Coastguard Worker             digest,
92*d289c2baSAndroid Build Coastguard Worker         })
93*d289c2baSAndroid Build Coastguard Worker     }
94*d289c2baSAndroid Build Coastguard Worker }
95*d289c2baSAndroid Build Coastguard Worker 
96*d289c2baSAndroid Build Coastguard Worker #[cfg(test)]
97*d289c2baSAndroid Build Coastguard Worker mod tests {
98*d289c2baSAndroid Build Coastguard Worker     use super::*;
99*d289c2baSAndroid Build Coastguard Worker 
100*d289c2baSAndroid Build Coastguard Worker     use crate::DescriptorError;
101*d289c2baSAndroid Build Coastguard Worker     use std::{fs, mem::size_of};
102*d289c2baSAndroid Build Coastguard Worker 
103*d289c2baSAndroid Build Coastguard Worker     /// A valid descriptor that we've pre-generated as test data.
test_contents() -> Vec<u8>104*d289c2baSAndroid Build Coastguard Worker     fn test_contents() -> Vec<u8> {
105*d289c2baSAndroid Build Coastguard Worker         fs::read("testdata/hash_descriptor.bin").unwrap()
106*d289c2baSAndroid Build Coastguard Worker     }
107*d289c2baSAndroid Build Coastguard Worker 
108*d289c2baSAndroid Build Coastguard Worker     #[test]
new_hash_descriptor_success()109*d289c2baSAndroid Build Coastguard Worker     fn new_hash_descriptor_success() {
110*d289c2baSAndroid Build Coastguard Worker         assert!(HashDescriptor::new(&test_contents()).is_ok());
111*d289c2baSAndroid Build Coastguard Worker     }
112*d289c2baSAndroid Build Coastguard Worker 
113*d289c2baSAndroid Build Coastguard Worker     #[test]
new_hash_descriptor_too_short_header_fails()114*d289c2baSAndroid Build Coastguard Worker     fn new_hash_descriptor_too_short_header_fails() {
115*d289c2baSAndroid Build Coastguard Worker         let bad_header_size = size_of::<AvbHashDescriptor>() - 1;
116*d289c2baSAndroid Build Coastguard Worker         assert_eq!(
117*d289c2baSAndroid Build Coastguard Worker             HashDescriptor::new(&test_contents()[..bad_header_size]).unwrap_err(),
118*d289c2baSAndroid Build Coastguard Worker             DescriptorError::InvalidHeader
119*d289c2baSAndroid Build Coastguard Worker         );
120*d289c2baSAndroid Build Coastguard Worker     }
121*d289c2baSAndroid Build Coastguard Worker 
122*d289c2baSAndroid Build Coastguard Worker     #[test]
new_hash_descriptor_too_short_contents_fails()123*d289c2baSAndroid Build Coastguard Worker     fn new_hash_descriptor_too_short_contents_fails() {
124*d289c2baSAndroid Build Coastguard Worker         // The last byte is padding, so we need to drop 2 bytes to trigger an error.
125*d289c2baSAndroid Build Coastguard Worker         let bad_contents_size = test_contents().len() - 2;
126*d289c2baSAndroid Build Coastguard Worker         assert_eq!(
127*d289c2baSAndroid Build Coastguard Worker             HashDescriptor::new(&test_contents()[..bad_contents_size]).unwrap_err(),
128*d289c2baSAndroid Build Coastguard Worker             DescriptorError::InvalidSize
129*d289c2baSAndroid Build Coastguard Worker         );
130*d289c2baSAndroid Build Coastguard Worker     }
131*d289c2baSAndroid Build Coastguard Worker }
132