blob: 569669926668a7b21346eff71f5420da582c7ec6 [file]
// Copyright 2023, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! GblOps trait that defines GBL callbacks.
//!
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(test)]
extern crate static_assertions;
use crate::digest::{Algorithm, Context, Digest};
use crate::error::{Error, Result};
#[cfg(feature = "alloc")]
use alloc::ffi::CString;
use avb::{IoError, Ops, PublicKeyForPartitionInfo};
use core::{ffi::CStr, fmt::Debug, ptr::NonNull};
/// TODO: b/312607649 - Placeholder. Use result type from `avb` when it is stable and public
pub type AvbResult<T> = core::result::Result<T, IoError>;
// https://stackoverflow.com/questions/41081240/idiomatic-callbacks-in-rust
// should we use traits for this? or optional/box FnMut?
//
/* TODO: b/312612203 - needed callbacks:
missing:
- validate_public_key_for_partition: None,
- key management => atx extension in callback => atx_ops: ptr::null_mut(), // support optional ATX.
*/
/// Trait that defines callbacks that can be provided to Gbl.
pub trait GblOps<D: Digest, C: Context<D>>: Ops + Debug {
/// Create digest object to use for hash computations.
///
/// Context interface allows to update value adding more data to process.
/// # Arguments
///
/// * algorithm - algorithm to use for hash computation.
fn new_digest(&self, algorithm: &'static Algorithm) -> C {
Context::new(algorithm)
}
/// Calculate digest of provided data with requested algorithm. Single use unlike [new_digest]
/// flow.
fn digest(&self, algorithm: &'static Algorithm, data: &[u8]) -> D {
let mut ctx = self.new_digest(algorithm);
ctx.update(data);
ctx.finish()
}
/// Callback for when fastboot mode is requested.
// Nevertype could be used here when it is stable https://github.com/serde-rs/serde/issues/812
fn do_fastboot(&self) -> Result<()> {
Err(Error::NotImplemented)
}
/// TODO: b/312607649 - placeholder interface for Gbl specific callbacks that uses alloc.
#[cfg(feature = "alloc")]
fn gbl_alloc_extra_action(&mut self, s: &str) -> Result<()>;
}
/// Default [GblOps] implementation that returns errors and does nothing.
#[derive(Debug)]
pub struct DefaultGblOps {}
impl Ops for DefaultGblOps {
fn validate_vbmeta_public_key(&mut self, _: &[u8], _: Option<&[u8]>) -> AvbResult<bool> {
Err(IoError::NotImplemented)
}
fn read_from_partition(&mut self, _: &CStr, _: i64, _: &mut [u8]) -> AvbResult<usize> {
Err(IoError::NotImplemented)
}
fn read_rollback_index(&mut self, _: usize) -> AvbResult<u64> {
Err(IoError::NotImplemented)
}
fn write_rollback_index(&mut self, _: usize, _: u64) -> AvbResult<()> {
Err(IoError::NotImplemented)
}
fn read_is_device_unlocked(&mut self) -> AvbResult<bool> {
Err(IoError::NotImplemented)
}
fn get_size_of_partition(&mut self, partition: &CStr) -> AvbResult<u64> {
Err(IoError::NotImplemented)
}
fn read_persistent_value(&mut self, name: &CStr, value: &mut [u8]) -> AvbResult<usize> {
Err(IoError::NotImplemented)
}
fn write_persistent_value(&mut self, name: &CStr, value: &[u8]) -> AvbResult<()> {
Err(IoError::NotImplemented)
}
fn erase_persistent_value(&mut self, name: &CStr) -> AvbResult<()> {
Err(IoError::NotImplemented)
}
fn validate_public_key_for_partition(
&mut self,
partition: &CStr,
public_key: &[u8],
public_key_metadata: Option<&[u8]>,
) -> AvbResult<PublicKeyForPartitionInfo> {
Err(IoError::NotImplemented)
}
}
impl<D, C> GblOps<D, C> for DefaultGblOps
where
D: Digest,
C: Context<D>,
{
#[cfg(feature = "alloc")]
fn gbl_alloc_extra_action(&mut self, s: &str) -> Result<()> {
let _c_string = CString::new(s);
Err(Error::Error)
}
}
#[cfg(test)]
static_assertions::const_assert_eq!(core::mem::size_of::<DefaultGblOps>(), 0);
impl DefaultGblOps {
/// Create new DefaultGblOps object
pub fn new() -> &'static mut Self {
let mut ptr: NonNull<Self> = NonNull::dangling();
// SAFETY: Self is a ZST, asserted above, and ptr is appropriately aligned and nonzero by
// NonNull::dangling()
unsafe { ptr.as_mut() }
}
}