blob: 57feb12341ecfa7abf630548390b59d920554c8d [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use zerocopy::byteorder::big_endian::{U32 as BigEndianU32, U64 as BigEndianU64};
use super::{HashDescriptor, HashDescriptorHeader, Salt, ALGORITHM, HASH_DESCRIPTOR_TAG};
/// A builder for `HashDescriptor` that is able to more flexibly create a HashDescriptor. This
/// can create HashDescriptors with omitted fields (e.g. one that has a name and size, but no
/// salt or digest).
#[derive(Debug, Default)]
pub struct RawHashDescriptorBuilder {
name: Option<String>,
size: Option<u64>,
salt: Option<Salt>,
digest: Option<[u8; 32]>,
flags: Option<u32>,
min_avb_version: Option<[u32; 2]>,
}
impl RawHashDescriptorBuilder {
/// Provide the minimum avb version for the descriptor
pub fn min_avb_version(self, min_avb_version: [u32; 2]) -> Self {
Self { min_avb_version: Some(min_avb_version), ..self }
}
/// Provide the name field for the HashDescriptor being built.
pub fn name(self, name: impl AsRef<str>) -> Self {
Self { name: Some(name.as_ref().to_owned()), ..self }
}
/// Provide the size field for the HashDescriptor being built.
pub fn size(self, size: u64) -> Self {
Self { size: Some(size), ..self }
}
/// Provide the salt field for the HashDescriptor being built.
pub fn salt(self, salt: Salt) -> Self {
Self { salt: Some(salt), ..self }
}
/// Provide the digest field directly for the HashDescriptor being built.
pub fn digest(self, digest: &[u8]) -> Self {
let mut bytes = [0u8; 32];
bytes.copy_from_slice(digest);
Self { digest: Some(bytes), ..self }
}
/// Provide the flags field for the HashDescriptor being built.
pub fn flags(self, flags: u32) -> Self {
Self { flags: Some(flags), ..self }
}
/// Calculate the digest for the passed-in image, and use that to create
/// a HashDescriptor from this builder.
pub fn build_with_digest_calculated_for(self, image: &[u8]) -> HashDescriptor {
let digest = HashDescriptor::calculate_digest_for_image(&self.salt, image);
self.digest(&digest).build()
}
/// Create the HashDescriptor from this builder.
pub fn build(self) -> HashDescriptor {
// Build the header with the information we have (this may not be a
// "useful" result, but it's what we've got).
let image_name_size = self.name.as_ref().map_or(0, |name| name.len() as u32);
let salt_size = match &self.salt {
Some(_) => 32,
_ => 0,
};
let digest_size = match &self.digest {
Some(digest) => digest.len() as u32,
_ => 0,
};
let header = HashDescriptorHeader {
tag: HASH_DESCRIPTOR_TAG.into(),
num_bytes_following: HashDescriptorHeader::calculate_num_bytes_following(
image_name_size,
salt_size,
digest_size,
)
.into(),
image_size: BigEndianU64::new(self.size.unwrap_or(0)),
hash_alg: HashDescriptorHeader::bytes_for_algorithm(ALGORITHM),
image_name_size: image_name_size.into(),
salt_size: salt_size.into(),
digest_size: digest_size.into(),
flags: BigEndianU32::new(self.flags.unwrap_or(0)),
pad: [0u8; 60],
};
HashDescriptor {
header,
image_name: self.name.unwrap_or("".to_owned()),
salt: self.salt,
digest: self.digest,
min_avb_version: self.min_avb_version,
}
}
}