xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/gbl_avb/ops.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Gbl AVB operations.
16 
17 use crate::{
18     gbl_avb::state::{BootStateColor, KeyValidationStatus},
19     gbl_print, gbl_println, GblOps,
20 };
21 use avb::{
22     cert_validate_vbmeta_public_key, CertOps, CertPermanentAttributes, IoError, IoResult,
23     Ops as AvbOps, PublicKeyForPartitionInfo, SlotVerifyData, SHA256_DIGEST_SIZE,
24 };
25 use core::{
26     cmp::{max, min},
27     ffi::CStr,
28 };
29 use liberror::Error;
30 use safemath::SafeNum;
31 use uuid::Uuid;
32 
33 // AVB cert tracks versions for the PIK and PSK; PRK cannot be changed so has no version info.
34 const AVB_CERT_NUM_KEY_VERSIONS: usize = 2;
35 
36 /// Implements avb ops callbacks for [GblOps].
37 pub struct GblAvbOps<'a, T> {
38     /// The underlying [GblOps].
39     pub gbl_ops: &'a mut T,
40     preloaded_partitions: &'a [(&'a str, &'a [u8])],
41     /// Used for storing key versions to be set (location, version).
42     ///
43     /// These will initially be `None`, but if using the cert extensions they will be updated during
44     /// verification. These values will not be automatically persisted to disk because whether to do
45     /// so depends on other factors such as slot success state; it's up to the user to persist them
46     /// post-verification if needed.
47     // If `array_map` is imported in the future, consider switching to it.
48     pub key_versions: [Option<(usize, u64)>; AVB_CERT_NUM_KEY_VERSIONS],
49     /// True to use the AVB cert extensions.
50     use_cert: bool,
51     /// Avb public key validation status reported by validate_vbmeta_public_key.
52     /// https://source.android.com/docs/security/features/verifiedboot/boot-flow#locked-devices-with-custom-root-of-trust
53     key_validation_status: Option<KeyValidationStatus>,
54 }
55 
56 impl<'a, 'p, 'q, T: GblOps<'p, 'q>> GblAvbOps<'a, T> {
57     /// Creates a new [GblAvbOps].
new( gbl_ops: &'a mut T, preloaded_partitions: &'a [(&'a str, &'a [u8])], use_cert: bool, ) -> Self58     pub fn new(
59         gbl_ops: &'a mut T,
60         preloaded_partitions: &'a [(&'a str, &'a [u8])],
61         use_cert: bool,
62     ) -> Self {
63         Self {
64             gbl_ops,
65             preloaded_partitions,
66             key_versions: [None; AVB_CERT_NUM_KEY_VERSIONS],
67             use_cert,
68             key_validation_status: None,
69         }
70     }
71 
72     /// Returns the size of a partition.
73     ///
74     /// This will only consider the [GblOps] partitions. To include preloaded partitions as well,
75     /// use [AvbOps::get_size_of_partition].
partition_size(&mut self, partition: &str) -> IoResult<u64>76     fn partition_size(&mut self, partition: &str) -> IoResult<u64> {
77         self.gbl_ops.partition_size(partition).or(Err(IoError::Io))?.ok_or(IoError::NoSuchPartition)
78     }
79 
80     /// Allowes implementation side to handle verification result.
handle_verification_result( &mut self, slot_verify: &SlotVerifyData, color: BootStateColor, ) -> IoResult<()>81     pub fn handle_verification_result(
82         &mut self,
83         slot_verify: &SlotVerifyData,
84         color: BootStateColor,
85     ) -> IoResult<()> {
86         let mut vbmeta = None;
87         let mut vbmeta_boot = None;
88         let mut vbmeta_system = None;
89         let mut vbmeta_vendor = None;
90 
91         // The Android build system automatically generates only the main vbmeta, but also allows
92         // to have separate chained partitions like vbmeta_system (for system, product, system_ext,
93         // etc.) or vbmeta_vendor (for vendor).
94         // https://android.googlesource.com/platform/external/avb/+/master/README.md#build-system-integration
95         //
96         // It may also integrate chained vbmeta into system level metadata partitions such as boot
97         // or init_boot, so they can be updated separately.
98         // https://android.googlesource.com/platform/external/avb/+/master/README.md#gki-2_0-integration
99         //
100         // Custom chained partitions are also supported by the Android build system, but we expect
101         // OEMs to follow about the same pattern.
102         // https://android-review.googlesource.com/q/Id671e2c3aee9ada90256381cce432927df03169b
103         for data in slot_verify.vbmeta_data() {
104             match data.partition_name().to_str().unwrap_or_default() {
105                 "vbmeta" => vbmeta = Some(data),
106                 "boot" => vbmeta_boot = Some(data),
107                 "vbmeta_system" => vbmeta_system = Some(data),
108                 "vbmeta_vendor" => vbmeta_vendor = Some(data),
109                 _ => {}
110             }
111         }
112 
113         let data = vbmeta.ok_or(IoError::NoSuchPartition)?;
114         let boot_data = vbmeta_boot.unwrap_or(data);
115         let system_data = vbmeta_system.unwrap_or(data);
116         let vendor_data = vbmeta_vendor.unwrap_or(data);
117 
118         let boot_os_version = boot_data.get_property_value("com.android.build.boot.os_version");
119         let boot_security_patch =
120             boot_data.get_property_value("com.android.build.boot.security_patch");
121 
122         let system_os_version =
123             system_data.get_property_value("com.android.build.system.os_version");
124         let system_security_patch =
125             system_data.get_property_value("com.android.build.system.security_patch");
126 
127         let vendor_os_version =
128             vendor_data.get_property_value("com.android.build.vendor.os_version");
129         let vendor_security_patch =
130             vendor_data.get_property_value("com.android.build.vendor.security_patch");
131 
132         self.gbl_ops.avb_handle_verification_result(
133             color,
134             // TODO(b/337846185): extract VBH from the command line provided by libavb.
135             None,
136             boot_os_version,
137             boot_security_patch,
138             system_os_version,
139             system_security_patch,
140             vendor_os_version,
141             vendor_security_patch,
142         )
143     }
144 
145     /// Get vbmeta public key validation status reported by validate_vbmeta_public_key.
key_validation_status(&self) -> IoResult<KeyValidationStatus>146     pub fn key_validation_status(&self) -> IoResult<KeyValidationStatus> {
147         self.key_validation_status.ok_or(IoError::NotImplemented)
148     }
149 }
150 
151 /// A helper function for converting `CStr` to `str`
cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E>152 fn cstr_to_str<E>(s: &CStr, err: E) -> Result<&str, E> {
153     Ok(s.to_str().or(Err(err))?)
154 }
155 
156 /// # Lifetimes
157 /// * `'a`: preloaded data lifetime
158 /// * `'b`: [GblOps] partition lifetime
159 impl<'a, 'b, 'c, T: GblOps<'b, 'c>> AvbOps<'a> for GblAvbOps<'a, T> {
read_from_partition( &mut self, partition: &CStr, offset: i64, buffer: &mut [u8], ) -> IoResult<usize>160     fn read_from_partition(
161         &mut self,
162         partition: &CStr,
163         offset: i64,
164         buffer: &mut [u8],
165     ) -> IoResult<usize> {
166         let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
167         let partition_size = SafeNum::from(self.partition_size(part_str)?);
168         let read_off = match offset < 0 {
169             true => partition_size - offset.abs(),
170             _ => SafeNum::from(offset),
171         };
172         let read_sz = partition_size - read_off;
173         let read_off = read_off.try_into().or(Err(IoError::RangeOutsidePartition))?;
174         let read_sz =
175             min(buffer.len(), read_sz.try_into().or(Err(IoError::RangeOutsidePartition))?);
176         self.gbl_ops.read_from_partition_sync(part_str, read_off, &mut buffer[..read_sz]).map_err(
177             |e| match e {
178                 Error::NotFound => IoError::NoSuchPartition,
179                 Error::ArithmeticOverflow(_) => IoError::RangeOutsidePartition,
180                 _ => IoError::Io,
181             },
182         )?;
183         Ok(read_sz)
184     }
185 
get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]>186     fn get_preloaded_partition(&mut self, partition: &CStr) -> IoResult<&'a [u8]> {
187         let part_str = cstr_to_str(partition, IoError::NotImplemented)?;
188         Ok(self
189             .preloaded_partitions
190             .iter()
191             .find(|(name, _)| *name == part_str)
192             .ok_or(IoError::NotImplemented)?
193             .1)
194     }
195 
validate_vbmeta_public_key( &mut self, public_key: &[u8], public_key_metadata: Option<&[u8]>, ) -> IoResult<bool>196     fn validate_vbmeta_public_key(
197         &mut self,
198         public_key: &[u8],
199         public_key_metadata: Option<&[u8]>,
200     ) -> IoResult<bool> {
201         let status = if self.use_cert {
202             match cert_validate_vbmeta_public_key(self, public_key, public_key_metadata)? {
203                 true => KeyValidationStatus::Valid,
204                 false => KeyValidationStatus::Invalid,
205             }
206         } else {
207             self.gbl_ops.avb_validate_vbmeta_public_key(public_key, public_key_metadata).or_else(
208                 |err| {
209                     // TODO(b/337846185): Remove fallback once AVB protocol implementation is
210                     // forced.
211                     fallback_not_implemented(
212                         self.gbl_ops,
213                         err,
214                         "validate_vbmeta_public_key",
215                         KeyValidationStatus::ValidCustomKey,
216                     )
217                 },
218             )?
219         };
220 
221         self.key_validation_status = Some(status);
222 
223         Ok(matches!(status, KeyValidationStatus::Valid | KeyValidationStatus::ValidCustomKey))
224     }
225 
read_rollback_index(&mut self, rollback_index_location: usize) -> IoResult<u64>226     fn read_rollback_index(&mut self, rollback_index_location: usize) -> IoResult<u64> {
227         self.gbl_ops.avb_read_rollback_index(rollback_index_location).or_else(|err| {
228             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
229             // forced.
230             fallback_not_implemented(self.gbl_ops, err, "read_rollback_index", 0)
231         })
232     }
233 
write_rollback_index(&mut self, rollback_index_location: usize, index: u64) -> IoResult<()>234     fn write_rollback_index(&mut self, rollback_index_location: usize, index: u64) -> IoResult<()> {
235         self.gbl_ops.avb_write_rollback_index(rollback_index_location, index).or_else(|err| {
236             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
237             // forced.
238             fallback_not_implemented(self.gbl_ops, err, "write_rollback_index", ())
239         })
240     }
241 
read_is_device_unlocked(&mut self) -> IoResult<bool>242     fn read_is_device_unlocked(&mut self) -> IoResult<bool> {
243         self.gbl_ops.avb_read_is_device_unlocked().or_else(|err| {
244             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
245             // forced.
246             fallback_not_implemented(self.gbl_ops, err, "read_is_device_unlocked", true)
247         })
248     }
249 
get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid>250     fn get_unique_guid_for_partition(&mut self, partition: &CStr) -> IoResult<Uuid> {
251         // The ops is only used to check that a partition exists. GUID is not used.
252         self.partition_size(cstr_to_str(partition, IoError::NoSuchPartition)?)?;
253         Ok(Uuid::nil())
254     }
255 
get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64>256     fn get_size_of_partition(&mut self, partition: &CStr) -> IoResult<u64> {
257         match self.get_preloaded_partition(partition) {
258             Ok(img) => Ok(img.len().try_into().unwrap()),
259             _ => {
260                 let part_str = cstr_to_str(partition, IoError::NoSuchPartition)?;
261                 self.partition_size(part_str)
262             }
263         }
264     }
265 
read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> IoResult<usize>266     fn read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> IoResult<usize> {
267         self.gbl_ops.avb_read_persistent_value(name, value).or_else(|err| {
268             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
269             // forced.
270             fallback_not_implemented(self.gbl_ops, err, "read_persistent_value", 0)
271         })
272     }
273 
write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> IoResult<()>274     fn write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> IoResult<()> {
275         self.gbl_ops.avb_write_persistent_value(name, value).or_else(|err| {
276             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
277             // forced.
278             fallback_not_implemented(self.gbl_ops, err, "write_persistent_value", ())
279         })
280     }
281 
erase_persistent_value(&mut self, name: &CStr) -> IoResult<()>282     fn erase_persistent_value(&mut self, name: &CStr) -> IoResult<()> {
283         self.gbl_ops.avb_erase_persistent_value(name).or_else(|err| {
284             // TODO(b/337846185): Remove fallback once AVB protocol implementation is
285             // forced.
286             fallback_not_implemented(self.gbl_ops, err, "erase_persistent_value", ())
287         })
288     }
289 
validate_public_key_for_partition( &mut self, _partition: &CStr, _public_key: &[u8], _public_key_metadata: Option<&[u8]>, ) -> IoResult<PublicKeyForPartitionInfo>290     fn validate_public_key_for_partition(
291         &mut self,
292         _partition: &CStr,
293         _public_key: &[u8],
294         _public_key_metadata: Option<&[u8]>,
295     ) -> IoResult<PublicKeyForPartitionInfo> {
296         // Not needed yet; eventually we will plumb this through [GblOps].
297         unreachable!();
298     }
299 
cert_ops(&mut self) -> Option<&mut dyn CertOps>300     fn cert_ops(&mut self) -> Option<&mut dyn CertOps> {
301         match self.use_cert {
302             true => Some(self),
303             false => None,
304         }
305     }
306 }
307 
308 /// [GblAvbOps] always implements [CertOps], but it's only used if `use_cert` is set.
309 impl<'a, 'b, T: GblOps<'a, 'b>> CertOps for GblAvbOps<'_, T> {
read_permanent_attributes( &mut self, attributes: &mut CertPermanentAttributes, ) -> IoResult<()>310     fn read_permanent_attributes(
311         &mut self,
312         attributes: &mut CertPermanentAttributes,
313     ) -> IoResult<()> {
314         self.gbl_ops.avb_cert_read_permanent_attributes(attributes)
315     }
316 
read_permanent_attributes_hash(&mut self) -> IoResult<[u8; SHA256_DIGEST_SIZE]>317     fn read_permanent_attributes_hash(&mut self) -> IoResult<[u8; SHA256_DIGEST_SIZE]> {
318         self.gbl_ops.avb_cert_read_permanent_attributes_hash()
319     }
320 
set_key_version(&mut self, rollback_index_location: usize, key_version: u64)321     fn set_key_version(&mut self, rollback_index_location: usize, key_version: u64) {
322         // Checks if there is already an allocated slot for this location.
323         let existing = self
324             .key_versions
325             .iter_mut()
326             .find_map(|v| v.as_mut().filter(|(loc, _)| *loc == rollback_index_location));
327         match existing {
328             Some((_, val)) => *val = max(*val, key_version),
329             _ => {
330                 // Finds an empty slot and stores the rollback index.
331                 *self
332                     .key_versions
333                     .iter_mut()
334                     .find(|v| v.is_none())
335                     .expect("Ran out of key version slots") =
336                     Some((rollback_index_location, key_version))
337             }
338         }
339     }
340 
get_random(&mut self, _: &mut [u8]) -> IoResult<()>341     fn get_random(&mut self, _: &mut [u8]) -> IoResult<()> {
342         // Not needed yet; eventually we will plumb this through [GblOps].
343         unimplemented!()
344     }
345 }
346 
fallback_not_implemented<'a, 'b, T>( ops: &mut impl GblOps<'a, 'b>, error: IoError, method_name: &str, value: T, ) -> IoResult<T>347 fn fallback_not_implemented<'a, 'b, T>(
348     ops: &mut impl GblOps<'a, 'b>,
349     error: IoError,
350     method_name: &str,
351     value: T,
352 ) -> IoResult<T> {
353     match error {
354         IoError::NotImplemented => {
355             gbl_println!(
356                 ops,
357                 "WARNING: UEFI GblEfiAvbProtocol.{} implementation is missing. This will not be \
358                 permitted in the future.",
359                 method_name,
360             );
361             Ok(value)
362         }
363         err => Err(err),
364     }
365 }
366 
367 #[cfg(test)]
368 mod test {
369     use super::*;
370     use crate::ops::test::{FakeGblOps, FakeGblOpsStorage};
371 
372     // Returns test data consisting of `size` incrementing bytes (0-255 repeating).
test_data(size: usize) -> Vec<u8>373     fn test_data(size: usize) -> Vec<u8> {
374         let mut data = vec![0u8; size];
375         for index in 0..data.len() {
376             data[index] = index as u8;
377         }
378         data
379     }
380 
381     #[test]
read_from_partition_positive_off()382     fn read_from_partition_positive_off() {
383         let mut storage = FakeGblOpsStorage::default();
384         storage.add_raw_device(c"test_part", test_data(512));
385 
386         let mut gbl_ops = FakeGblOps::new(&storage);
387         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
388 
389         // Positive offset.
390         let mut out = [0u8; 4];
391         assert_eq!(avb_ops.read_from_partition(c"test_part", 1, &mut out[..]), Ok(4));
392         assert_eq!(out, [1, 2, 3, 4]);
393     }
394 
395     #[test]
read_from_partition_negative_off()396     fn read_from_partition_negative_off() {
397         let mut storage = FakeGblOpsStorage::default();
398         storage.add_raw_device(c"test_part", test_data(512));
399 
400         let mut gbl_ops = FakeGblOps::new(&storage);
401         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
402 
403         // Negative offset should wrap from the end
404         let mut out = [0u8; 6];
405         assert_eq!(avb_ops.read_from_partition(c"test_part", -6, &mut out[..]), Ok(6));
406         assert_eq!(out, [0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF]);
407     }
408 
409     #[test]
read_from_partition_partial_read()410     fn read_from_partition_partial_read() {
411         let mut storage = FakeGblOpsStorage::default();
412         storage.add_raw_device(c"test_part", test_data(512));
413 
414         let mut gbl_ops = FakeGblOps::new(&storage);
415         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
416 
417         // Reading past the end of the partition should truncate.
418         let mut out = [0u8; 6];
419         assert_eq!(avb_ops.read_from_partition(c"test_part", -3, &mut out[..]), Ok(3));
420         assert_eq!(out, [0xFD, 0xFE, 0xFF, 0, 0, 0]);
421     }
422 
423     #[test]
read_from_partition_out_of_bounds()424     fn read_from_partition_out_of_bounds() {
425         let mut storage = FakeGblOpsStorage::default();
426         storage.add_raw_device(c"test_part", test_data(512));
427 
428         let mut gbl_ops = FakeGblOps::new(&storage);
429         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
430 
431         // Reads starting out of bounds should fail.
432         let mut out = [0u8; 4];
433         assert_eq!(
434             avb_ops.read_from_partition(c"test_part", 513, &mut out[..]),
435             Err(IoError::RangeOutsidePartition)
436         );
437         assert_eq!(
438             avb_ops.read_from_partition(c"test_part", -513, &mut out[..]),
439             Err(IoError::RangeOutsidePartition)
440         );
441     }
442 
443     #[test]
read_from_partition_unknown_part()444     fn read_from_partition_unknown_part() {
445         let mut gbl_ops = FakeGblOps::new(&[]);
446         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
447 
448         let mut out = [0u8; 4];
449         assert_eq!(
450             avb_ops.read_from_partition(c"unknown_part", 0, &mut out[..]),
451             Err(IoError::NoSuchPartition)
452         );
453     }
454 
455     #[test]
set_key_version_default()456     fn set_key_version_default() {
457         let mut gbl_ops = FakeGblOps::new(&[]);
458         let avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
459 
460         assert_eq!(avb_ops.key_versions, [None, None]);
461     }
462 
463     #[test]
set_key_version_once()464     fn set_key_version_once() {
465         let mut gbl_ops = FakeGblOps::new(&[]);
466         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
467 
468         avb_ops.set_key_version(5, 10);
469         assert_eq!(avb_ops.key_versions, [Some((5, 10)), None]);
470     }
471 
472     #[test]
set_key_version_twice()473     fn set_key_version_twice() {
474         let mut gbl_ops = FakeGblOps::new(&[]);
475         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
476 
477         avb_ops.set_key_version(5, 10);
478         avb_ops.set_key_version(20, 40);
479         assert_eq!(avb_ops.key_versions, [Some((5, 10)), Some((20, 40))]);
480     }
481 
482     #[test]
set_key_version_overwrite()483     fn set_key_version_overwrite() {
484         let mut gbl_ops = FakeGblOps::new(&[]);
485         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
486 
487         avb_ops.set_key_version(5, 10);
488         avb_ops.set_key_version(20, 40);
489         avb_ops.set_key_version(5, 100);
490         assert_eq!(avb_ops.key_versions, [Some((5, 100)), Some((20, 40))]);
491     }
492 
493     // AVB's key version callback cannot return an error, so if it fails we panic.
494     //
495     // It's possible we could stash the failure somewhere and check it later, but we'd have to be
496     // very careful, as failing to check the status would be a security vulnerability. For now it's
497     // safer to panic, and we only ever expect the PSK and PIK to have key versions.
498     #[test]
499     #[should_panic(expected = "Ran out of key version slots")]
set_key_version_overflow()500     fn set_key_version_overflow() {
501         let mut gbl_ops = FakeGblOps::new(&[]);
502         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
503 
504         avb_ops.set_key_version(5, 10);
505         avb_ops.set_key_version(20, 40);
506         avb_ops.set_key_version(40, 100);
507     }
508 
509     #[test]
validate_vbmeta_public_key_valid()510     fn validate_vbmeta_public_key_valid() {
511         let mut gbl_ops = FakeGblOps::new(&[]);
512         gbl_ops.avb_key_validation_status = Some(Ok(KeyValidationStatus::Valid));
513 
514         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
515         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(true));
516         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::Valid));
517     }
518 
519     #[test]
validate_vbmeta_public_key_valid_custom_key()520     fn validate_vbmeta_public_key_valid_custom_key() {
521         let mut gbl_ops = FakeGblOps::new(&[]);
522         gbl_ops.avb_key_validation_status = Some(Ok(KeyValidationStatus::ValidCustomKey));
523 
524         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
525         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(true));
526         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::ValidCustomKey));
527     }
528 
529     #[test]
validate_vbmeta_public_key_invalid()530     fn validate_vbmeta_public_key_invalid() {
531         let mut gbl_ops = FakeGblOps::new(&[]);
532         gbl_ops.avb_key_validation_status = Some(Ok(KeyValidationStatus::Invalid));
533 
534         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
535         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(false));
536         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::Invalid));
537     }
538 
539     #[test]
validate_vbmeta_public_key_failed()540     fn validate_vbmeta_public_key_failed() {
541         let mut gbl_ops = FakeGblOps::new(&[]);
542         gbl_ops.avb_key_validation_status = Some(Err(IoError::Io));
543 
544         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
545         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Err(IoError::Io));
546         assert!(avb_ops.key_validation_status().is_err());
547     }
548 
549     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
550     #[test]
validate_vbmeta_public_key_not_implemented()551     fn validate_vbmeta_public_key_not_implemented() {
552         let mut gbl_ops = FakeGblOps::new(&[]);
553         gbl_ops.avb_key_validation_status = Some(Err(IoError::NotImplemented));
554 
555         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
556 
557         assert_eq!(avb_ops.validate_vbmeta_public_key(&[], None), Ok(true));
558         assert_eq!(avb_ops.key_validation_status(), Ok(KeyValidationStatus::ValidCustomKey));
559     }
560 
561     #[test]
read_rollback_index_read_value()562     fn read_rollback_index_read_value() {
563         const EXPECTED_INDEX: usize = 1;
564         const EXPECTED_VALUE: u64 = 100;
565 
566         let mut gbl_ops = FakeGblOps::new(&[]);
567         gbl_ops.avb_ops.rollbacks.insert(EXPECTED_INDEX, Ok(EXPECTED_VALUE));
568 
569         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
570         assert_eq!(avb_ops.read_rollback_index(EXPECTED_INDEX), Ok(EXPECTED_VALUE));
571     }
572 
573     #[test]
read_rollback_index_error_handled()574     fn read_rollback_index_error_handled() {
575         let mut gbl_ops = FakeGblOps::new(&[]);
576 
577         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
578         assert_eq!(avb_ops.read_rollback_index(0), Err(IoError::Io));
579     }
580 
581     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
582     #[test]
read_rollback_index_not_implemented()583     fn read_rollback_index_not_implemented() {
584         let mut gbl_ops = FakeGblOps::new(&[]);
585         gbl_ops.avb_ops.rollbacks.insert(0, Err(IoError::NotImplemented));
586 
587         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
588         assert_eq!(avb_ops.read_rollback_index(0), Ok(0));
589     }
590 
591     #[test]
write_rollback_index_write_value()592     fn write_rollback_index_write_value() {
593         const EXPECTED_INDEX: usize = 1;
594         const EXPECTED_VALUE: u64 = 100;
595 
596         let mut gbl_ops = FakeGblOps::new(&[]);
597 
598         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
599         assert_eq!(avb_ops.write_rollback_index(EXPECTED_INDEX, EXPECTED_VALUE), Ok(()));
600         assert_eq!(
601             gbl_ops.avb_ops.rollbacks.get(&EXPECTED_INDEX),
602             Some(Ok(EXPECTED_VALUE)).as_ref()
603         );
604     }
605 
606     #[test]
write_rollback_index_error_handled()607     fn write_rollback_index_error_handled() {
608         let mut gbl_ops = FakeGblOps::new(&[]);
609         gbl_ops.avb_ops.rollbacks.insert(0, Err(IoError::Io));
610 
611         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
612         assert_eq!(avb_ops.write_rollback_index(0, 0), Err(IoError::Io));
613     }
614 
615     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
616     #[test]
write_rollback_index_not_implemented()617     fn write_rollback_index_not_implemented() {
618         let mut gbl_ops = FakeGblOps::new(&[]);
619         gbl_ops.avb_ops.rollbacks.insert(0, Err(IoError::NotImplemented));
620 
621         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
622         assert_eq!(avb_ops.write_rollback_index(0, 0), Ok(()));
623     }
624 
625     #[test]
read_is_device_unlocked_value_obtained()626     fn read_is_device_unlocked_value_obtained() {
627         let mut gbl_ops = FakeGblOps::new(&[]);
628         gbl_ops.avb_ops.unlock_state = Ok(true);
629 
630         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
631 
632         assert_eq!(avb_ops.read_is_device_unlocked(), Ok(true));
633     }
634 
635     #[test]
read_is_device_unlocked_error_handled()636     fn read_is_device_unlocked_error_handled() {
637         let mut gbl_ops = FakeGblOps::new(&[]);
638         gbl_ops.avb_ops.unlock_state = Err(IoError::Io);
639 
640         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
641         assert_eq!(avb_ops.read_is_device_unlocked(), Err(IoError::Io));
642     }
643 
644     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
645     #[test]
read_is_device_unlocked_not_implemented()646     fn read_is_device_unlocked_not_implemented() {
647         let mut gbl_ops = FakeGblOps::new(&[]);
648         gbl_ops.avb_ops.unlock_state = Err(IoError::NotImplemented);
649 
650         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
651         assert_eq!(avb_ops.read_is_device_unlocked(), Ok(true));
652     }
653 
654     #[test]
read_persistent_value_success()655     fn read_persistent_value_success() {
656         const EXPECTED_NAME: &CStr = c"test";
657         const EXPECTED_VALUE: &[u8] = b"test";
658 
659         let mut gbl_ops = FakeGblOps::new(&[]);
660         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Ok(EXPECTED_VALUE));
661 
662         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
663         let mut buffer = [0u8; EXPECTED_VALUE.len()];
664         assert_eq!(
665             avb_ops.read_persistent_value(EXPECTED_NAME, &mut buffer),
666             Ok(EXPECTED_VALUE.len())
667         );
668         assert_eq!(buffer, EXPECTED_VALUE);
669     }
670 
671     #[test]
read_persistent_value_error()672     fn read_persistent_value_error() {
673         const EXPECTED_NAME: &CStr = c"test";
674 
675         let mut gbl_ops = FakeGblOps::new(&[]);
676         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::Io));
677 
678         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
679         let mut buffer = [0u8; 4];
680         assert_eq!(avb_ops.read_persistent_value(EXPECTED_NAME, &mut buffer), Err(IoError::Io));
681     }
682 
683     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
684     #[test]
read_persistent_value_not_implemented()685     fn read_persistent_value_not_implemented() {
686         const EXPECTED_NAME: &CStr = c"test";
687 
688         let mut gbl_ops = FakeGblOps::new(&[]);
689         gbl_ops
690             .avb_ops
691             .add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::NotImplemented));
692 
693         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
694         let mut buffer = [0u8; 0];
695         assert_eq!(avb_ops.read_persistent_value(EXPECTED_NAME, &mut buffer), Ok(0));
696     }
697 
698     #[test]
write_persistent_value_success()699     fn write_persistent_value_success() {
700         const EXPECTED_NAME: &CStr = c"test";
701         const EXPECTED_VALUE: &[u8] = b"test";
702 
703         let mut gbl_ops = FakeGblOps::new(&[]);
704 
705         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
706         assert_eq!(avb_ops.write_persistent_value(EXPECTED_NAME, EXPECTED_VALUE), Ok(()));
707 
708         assert_eq!(
709             gbl_ops.avb_ops.persistent_values.get(EXPECTED_NAME.to_str().unwrap()),
710             Some(Ok(EXPECTED_VALUE.to_vec())).as_ref()
711         );
712     }
713 
714     #[test]
write_persistent_value_error()715     fn write_persistent_value_error() {
716         const EXPECTED_NAME: &CStr = c"test";
717         const EXPECTED_VALUE: &[u8] = b"test";
718 
719         let mut gbl_ops = FakeGblOps::new(&[]);
720         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::Io));
721 
722         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
723         assert_eq!(avb_ops.write_persistent_value(EXPECTED_NAME, EXPECTED_VALUE), Err(IoError::Io));
724     }
725 
726     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
727     #[test]
write_persistent_value_not_implemented()728     fn write_persistent_value_not_implemented() {
729         const EXPECTED_NAME: &CStr = c"test";
730         const EXPECTED_VALUE: &[u8] = b"test";
731 
732         let mut gbl_ops = FakeGblOps::new(&[]);
733         gbl_ops
734             .avb_ops
735             .add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::NotImplemented));
736 
737         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
738         assert_eq!(avb_ops.write_persistent_value(EXPECTED_NAME, EXPECTED_VALUE), Ok(()));
739     }
740 
741     #[test]
erase_persistent_value_success()742     fn erase_persistent_value_success() {
743         const EXPECTED_NAME: &CStr = c"test";
744 
745         let mut gbl_ops = FakeGblOps::new(&[]);
746         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Ok(b"test"));
747 
748         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
749         assert_eq!(avb_ops.erase_persistent_value(EXPECTED_NAME), Ok(()));
750 
751         assert!(!gbl_ops.avb_ops.persistent_values.contains_key(EXPECTED_NAME.to_str().unwrap()));
752     }
753 
754     #[test]
erase_persistent_value_error()755     fn erase_persistent_value_error() {
756         const EXPECTED_NAME: &CStr = c"test";
757 
758         let mut gbl_ops = FakeGblOps::new(&[]);
759         gbl_ops.avb_ops.add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::Io));
760 
761         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
762         assert_eq!(avb_ops.erase_persistent_value(EXPECTED_NAME), Err(IoError::Io));
763     }
764 
765     // TODO(b/337846185): Remove test once AVB protocol implementation is forced.
766     #[test]
erase_persistent_value_not_implemented()767     fn erase_persistent_value_not_implemented() {
768         const EXPECTED_NAME: &CStr = c"test";
769 
770         let mut gbl_ops = FakeGblOps::new(&[]);
771         gbl_ops
772             .avb_ops
773             .add_persistent_value(EXPECTED_NAME.to_str().unwrap(), Err(IoError::NotImplemented));
774 
775         let mut avb_ops = GblAvbOps::new(&mut gbl_ops, &[], false);
776         assert_eq!(avb_ops.erase_persistent_value(EXPECTED_NAME), Ok(()));
777     }
778 }
779