blob: cb02f39f8f1e7ed6cfaabb774da110a4d19dc87a [file] [log] [blame]
// Copyright 2022, 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.
extern crate alloc;
use alloc::{
string::{String, ToString},
vec::Vec,
};
use apkverify::SignatureAlgorithmID;
use core::fmt;
use serde::{Deserialize, Serialize};
/// An Avmd struct contains
/// - A header with version information that allows rollback when needed.
/// - A list of descriptors that describe different images.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Avmd {
header: Header,
descriptors: Vec<Descriptor>,
}
impl fmt::Display for Avmd {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Descriptors:")?;
for descriptor in &self.descriptors {
write!(f, "{}", descriptor)?;
}
Ok(())
}
}
impl Avmd {
/// Creates an instance of Avmd with a given list of descriptors.
pub fn new(descriptors: Vec<Descriptor>) -> Avmd {
Avmd { header: Header::default(), descriptors }
}
}
static AVMD_MAGIC: u32 = 0x444d5641;
static AVMD_VERSION_MAJOR: u16 = 1;
static AVMD_VERSION_MINOR: u16 = 0;
/// Header information for AVMD.
#[derive(Serialize, Deserialize, Debug, Clone)]
struct Header {
magic: u32,
version_major: u16,
version_minor: u16,
}
impl Default for Header {
fn default() -> Self {
Header {
magic: AVMD_MAGIC,
version_major: AVMD_VERSION_MAJOR,
version_minor: AVMD_VERSION_MINOR,
}
}
}
/// AVMD descriptor.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Descriptor {
/// Descriptor type for the VBMeta images.
VbMeta(VbMetaDescriptor),
/// Descriptor type for APK.
Apk(ApkDescriptor),
}
impl fmt::Display for Descriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Descriptor::VbMeta(descriptor) => write!(f, "{}", descriptor),
Descriptor::Apk(descriptor) => write!(f, "{}", descriptor),
}
}
}
/// VbMeta descriptor.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct VbMetaDescriptor {
/// The identifier of this resource.
#[serde(flatten)]
pub resource: ResourceIdentifier,
/// The SHA-512 [VBMeta digest][] calculated from the top-level VBMeta image.
///
/// [VBMeta digest]: https://android.googlesource.com/platform/external/avb/+/master/README.md#the-vbmeta-digest
pub vbmeta_digest: Vec<u8>,
}
impl fmt::Display for VbMetaDescriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, " VBMeta descriptor:")?;
writeln!(f, " namespace: {}", self.resource.namespace)?;
writeln!(f, " name: {}", self.resource.name)?;
writeln!(f, " vbmeta digest: {}", hex::encode(&self.vbmeta_digest))?;
Ok(())
}
}
/// APK descriptor.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ApkDescriptor {
/// The identifier of this resource.
#[serde(flatten)]
pub resource: ResourceIdentifier,
/// The ID of the algoithm used to sign the APK.
/// It should be one of the algorithms in the [list][].
///
/// [list]: https://source.android.com/security/apksigning/v2#signature-algorithm-ids
pub signature_algorithm_id: SignatureAlgorithmID,
/// Digest of the APK's v3 signing block. TODO: fix
pub apk_digest: Vec<u8>,
}
impl fmt::Display for ApkDescriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, " APK descriptor:")?;
writeln!(f, " namespace: {}", self.resource.namespace)?;
writeln!(f, " name: {}", self.resource.name)?;
writeln!(f, " Signing algorithm ID: {:#04x}", self.signature_algorithm_id.to_u32())?;
writeln!(f, " APK digest: {}", hex::encode(&self.apk_digest))?;
Ok(())
}
}
/// Resource identifier regroups information to identify resources.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ResourceIdentifier {
/// Namespace of the resource.
namespace: String,
/// Name of the resource.
name: String,
}
impl ResourceIdentifier {
/// Creates an instance of ResourceIdentifier with the given
/// namespace and name.
pub fn new(namespace: &str, name: &str) -> ResourceIdentifier {
ResourceIdentifier { namespace: namespace.to_string(), name: name.to_string() }
}
}