Use repr(C) structs instead of offsets and lengths in the signer.
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/lib/manifest.h b/sw/device/silicon_creator/lib/manifest.h
index 0271a62..93174c0 100644
--- a/sw/device/silicon_creator/lib/manifest.h
+++ b/sw/device/silicon_creator/lib/manifest.h
@@ -27,6 +27,10 @@
* integrity and authenticity of the next stage before handing over execution.
*
* Use of this struct for stages following BL0 is optional.
+ *
+ * Note: The definitions in
+ * sw/host/rom_ext_image_tools/signer/image/src/manifest.rs must be updated if
+ * this struct is modified. Please see the instructions in that file.
*/
typedef struct manifest {
/**
diff --git a/sw/host/rom_ext_image_tools/signer/Cargo.lock b/sw/host/rom_ext_image_tools/signer/Cargo.lock
index 775f594..2655a0f 100644
--- a/sw/host/rom_ext_image_tools/signer/Cargo.lock
+++ b/sw/host/rom_ext_image_tools/signer/Cargo.lock
@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+version = 3
+
[[package]]
name = "anyhow"
version = "1.0.40"
@@ -7,6 +9,18 @@
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -33,6 +47,15 @@
]
[[package]]
+name = "memoffset"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "mundane"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -87,7 +110,9 @@
name = "rom_ext_image"
version = "0.1.0"
dependencies = [
+ "memoffset",
"thiserror",
+ "zerocopy",
]
[[package]]
@@ -97,6 +122,7 @@
"anyhow",
"mundane",
"rom_ext_image",
+ "zerocopy",
]
[[package]]
@@ -167,19 +193,31 @@
]
[[package]]
-name = "thiserror"
-version = "1.0.24"
+name = "synstructure"
+version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
+checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
+dependencies = [
+ "proc-macro2 1.0.26",
+ "quote 1.0.9",
+ "syn 1.0.72",
+ "unicode-xid 0.2.2",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.24"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
+checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d"
dependencies = [
"proc-macro2 1.0.26",
"quote 1.0.9",
@@ -197,3 +235,24 @@
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "zerocopy"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e59ec1d2457bd6c0dd89b50e7d9d6b0b647809bf3f0a59ac85557046950b7b2"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0af017aca1fa6181f5dd7a802456fe6f7666ecdcc18d0910431f0fc89d474e51"
+dependencies = [
+ "proc-macro2 1.0.26",
+ "syn 1.0.72",
+ "synstructure",
+]
diff --git a/sw/host/rom_ext_image_tools/signer/Cargo.toml b/sw/host/rom_ext_image_tools/signer/Cargo.toml
index 4aeeb3e..4510720 100644
--- a/sw/host/rom_ext_image_tools/signer/Cargo.toml
+++ b/sw/host/rom_ext_image_tools/signer/Cargo.toml
@@ -24,8 +24,9 @@
debug = true
[dependencies]
-rom_ext_image = { path = "image" }
anyhow = "1.0.40"
+rom_ext_image = { path = "image" }
+zerocopy = "0.5.0"
[dependencies.mundane]
version = "0.4.4"
diff --git a/sw/host/rom_ext_image_tools/signer/image/Cargo.toml b/sw/host/rom_ext_image_tools/signer/image/Cargo.toml
index 35cb230..14b5f31 100644
--- a/sw/host/rom_ext_image_tools/signer/image/Cargo.toml
+++ b/sw/host/rom_ext_image_tools/signer/image/Cargo.toml
@@ -9,4 +9,7 @@
edition = "2018"
[dependencies]
+memoffset = "0.6.0"
thiserror = "1.0.24"
+zerocopy = "0.5.0"
+
diff --git a/sw/host/rom_ext_image_tools/signer/image/src/image.rs b/sw/host/rom_ext_image_tools/signer/image/src/image.rs
index 01c3355..e55e9ee 100644
--- a/sw/host/rom_ext_image_tools/signer/image/src/image.rs
+++ b/sw/host/rom_ext_image_tools/signer/image/src/image.rs
@@ -6,72 +6,83 @@
#![deny(unused)]
#![deny(unsafe_code)]
-use crate::manifest;
+use std::mem::size_of;
+use std::ops::Deref;
+use std::ops::DerefMut;
+
+use memoffset::offset_of;
use thiserror::Error;
+use zerocopy::AsBytes;
+use zerocopy::LayoutVerified;
+
+use crate::manifest::Manifest;
#[derive(Error, Debug, PartialEq)]
pub enum ImageError {
- #[error("Expected at most {len} bytes for offset {offset}, received {data_len}.")]
- FieldData {
- offset: usize,
- len: usize,
- data_len: usize,
- },
+ #[error("Failed to parse image manifest.")]
+ Parse,
}
-/// A thin wrapper around a Vec to help with setting ROM_EXT manifest fields.
+/// A thin wrapper around manifest and payload buffers to help with setting manifest fields and
+/// signing the image.
#[derive(Debug)]
-pub struct Image {
- data: Vec<u8>,
+pub struct Image<'a> {
+ pub manifest: LayoutVerified<&'a mut [u8], Manifest>,
+ pub payload: &'a [u8],
}
-impl Image {
- /// Sets the value of a ROM_EXT manifest field.
- pub fn set_manifest_field<I>(
- &mut self,
- field: &manifest::ManifestField,
- field_data: I,
- ) -> Result<(), ImageError>
- where
- I: IntoIterator<Item = u8>,
- I::IntoIter: ExactSizeIterator,
- {
- let field_data = field_data.into_iter();
- if field_data.len() > field.size_bytes {
- Err(ImageError::FieldData {
- offset: field.offset,
- len: field.size_bytes,
- data_len: field_data.len(),
- })
- } else {
- self.data.splice(
- field.offset..(field.offset + field_data.len()),
- field_data,
- );
- Ok(())
+impl<'a> Image<'a> {
+ pub fn new(
+ manifest_buffer: &'a mut ManifestBuffer,
+ payload: &'a [u8],
+ ) -> Result<Image<'a>, ImageError> {
+ let manifest = LayoutVerified::new(&mut **manifest_buffer)
+ .ok_or(ImageError::Parse)?;
+ Ok(Self { manifest, payload })
+ }
+
+ pub fn bytes(&self) -> Vec<u8> {
+ [self.manifest.as_bytes(), self.payload].concat()
+ }
+
+ pub fn signed_bytes(&self) -> Vec<u8> {
+ self.bytes().split_off(offset_of!(Manifest, image_length))
+ }
+}
+
+/// A buffer with the same size and alignment as `Manifest`.
+pub struct ManifestBuffer {
+ buf: [u8; size_of::<Manifest>()],
+ // This forces this struct to have the same alignment as `Manifest`.
+ _align: [Manifest; 0],
+}
+
+impl ManifestBuffer {
+ pub fn new() -> Self {
+ Self {
+ buf: [0u8; size_of::<Manifest>()],
+ _align: [],
}
}
+}
- /// Returns the signed bytes of the image.
- pub fn signed_bytes(&self) -> &[u8] {
- &self.data[manifest::ROM_EXT_SIGNED_AREA_START_OFFSET..]
- }
-
- /// Returns the size of the image in number of bytes.
- pub fn len(&self) -> usize {
- self.data.len()
+impl Default for ManifestBuffer {
+ fn default() -> Self {
+ Self::new()
}
}
-impl AsRef<[u8]> for Image {
- fn as_ref(&self) -> &[u8] {
- &self.data
+impl Deref for ManifestBuffer {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ &self.buf
}
}
-impl From<Vec<u8>> for Image {
- fn from(data: Vec<u8>) -> Self {
- Image { data }
+impl DerefMut for ManifestBuffer {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.buf
}
}
@@ -81,43 +92,29 @@
#[test]
fn test_set_manifest_field() -> Result<(), ImageError> {
- let mut image = Image::from(vec![0; 1024]);
- let field = manifest::ROM_EXT_IMAGE_LENGTH;
- let val: [u8; 4] = [0xA5; 4];
- image.set_manifest_field(&field, val.iter().cloned())?;
- assert_eq!(
- image.as_ref()[field.offset..field.offset + field.size_bytes],
- val
- );
+ let mut manifest_buffer = ManifestBuffer::new();
+ let payload = [0u8; 0];
+ let mut image = Image::new(&mut manifest_buffer, &payload)?;
+ let identifier: u32 = 0x01020304;
+ image.manifest.identifier = identifier;
+ for i in 0..4 {
+ assert_eq!(manifest_buffer[i], identifier.to_le_bytes()[i]);
+ }
Ok(())
}
#[test]
- fn test_set_manifest_field_error() {
- let mut image = Image::from(vec![0; 1024]);
- let field = manifest::ROM_EXT_IMAGE_LENGTH;
- let val: [u8; 6] = [0xA5; 6];
- assert_eq!(
- image.set_manifest_field(&field, val.iter().cloned()),
- Err(ImageError::FieldData {
- offset: field.offset,
- len: field.size_bytes,
- data_len: 6
- })
- );
- }
-
- #[test]
- fn test_signed_bytes() -> Result<(), ImageError> {
- let mut image = Image::from(vec![0; 1024]);
- let field = manifest::ROM_EXT_IMAGE_SIGNATURE;
- let val: [u8; manifest::ROM_EXT_IMAGE_SIGNATURE.size_bytes] =
- [0xA5; manifest::ROM_EXT_IMAGE_SIGNATURE.size_bytes];
- image.set_manifest_field(&field, val.iter().cloned())?;
- assert_eq!(
- image.as_ref()[field.offset..field.offset + field.size_bytes],
- val
- );
+ fn test_bytes() -> Result<(), ImageError> {
+ let mut manifest_buffer = ManifestBuffer::new();
+ let payload = [5u8, 6u8, 7u8, 8u8];
+ let mut image = Image::new(&mut manifest_buffer, &payload)?;
+ let identifier: u32 = 0x01020304;
+ image.manifest.identifier = identifier;
+ let bytes = image.bytes();
+ for i in 0..4 {
+ assert_eq!(bytes[i], manifest_buffer[i]);
+ assert_eq!(bytes[size_of::<Manifest>() + i], payload[i]);
+ }
Ok(())
}
}
diff --git a/sw/host/rom_ext_image_tools/signer/image/src/manifest.rs b/sw/host/rom_ext_image_tools/signer/image/src/manifest.rs
index 2959964..8e6c6a9 100644
--- a/sw/host/rom_ext_image_tools/signer/image/src/manifest.rs
+++ b/sw/host/rom_ext_image_tools/signer/image/src/manifest.rs
@@ -1,111 +1,94 @@
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
-//
-// ---------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! ----------
-// PLEASE DO NOT HAND-EDIT THIS FILE. IT HAS BEEN AUTO-GENERATED WITH THE
-// FOLLOWING COMMAND:
-// util/rom-ext-manifest-generator.py
-// --input-dir=sw/device/silicon_creator/rom_exts
-// --output-dir=<destination dir>
-// --output-files=rust
-pub struct ManifestField {
- pub offset: usize,
- pub size_bytes: usize,
+//! Structs for reading and writing manifests of flash boot stage images.
+//!
+//! Note: The structs below must match the definitions in
+//! sw/device/silicon_creator/lib/manifest.h.
+
+#![deny(warnings)]
+#![deny(unused)]
+#![deny(unsafe_code)]
+
+use std::mem::size_of;
+
+use memoffset::offset_of;
+use zerocopy::AsBytes;
+use zerocopy::FromBytes;
+
+// Currently, these definitions must be updated manually but they can be
+// generated using the following commands (requires bindgen):
+// cargo install bindgen
+// cd "${REPO_TOP}"
+// bindgen --allowlist-type manifest_t --allowlist-var "MANIFEST_.*" \
+// --no-doc-comments --no-layout-tests \
+// sw/device/silicon_creator/lib/manifest.h \
+// -- -I./ -Isw/device/lib/base/freestanding
+
+pub const MANIFEST_SIZE: u32 = 880;
+
+/// Manifest for boot stage images stored in flash.
+#[repr(C)]
+#[derive(FromBytes, AsBytes, Debug, Default)]
+pub struct Manifest {
+ pub identifier: u32,
+ pub reserved0: u32,
+ pub signature: SigverifyRsaBuffer,
+ pub image_length: u32,
+ pub image_version: u32,
+ pub image_timestamp: u64,
+ pub exponent: u32,
+ pub reserved1: u32,
+ pub usage_constraints: [u32; 8usize],
+ pub lockdown_info: [u32; 4usize],
+ pub modulus: SigverifyRsaBuffer,
+ pub extension0_offset: u32,
+ pub extension0_checksum: u32,
+ pub extension1_offset: u32,
+ pub extension1_checksum: u32,
+ pub extension2_offset: u32,
+ pub extension2_checksum: u32,
+ pub extension3_offset: u32,
+ pub extension3_checksum: u32,
}
-pub const ROM_EXT_MANIFEST_IDENTIFIER: ManifestField = ManifestField {
- offset: 0,
- size_bytes: 4,
-};
+/// A type that holds 96 32-bit words for RSA-3072.
+#[repr(C)]
+#[derive(FromBytes, AsBytes, Debug)]
+pub struct SigverifyRsaBuffer {
+ pub data: [u32; 96usize],
+}
-pub const ROM_EXT_IMAGE_SIGNATURE: ManifestField = ManifestField {
- offset: 8,
- size_bytes: 384,
-};
+impl Default for SigverifyRsaBuffer {
+ fn default() -> Self {
+ Self { data: [0; 96usize] }
+ }
+}
-pub const ROM_EXT_IMAGE_LENGTH: ManifestField = ManifestField {
- offset: 392,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_IMAGE_VERSION: ManifestField = ManifestField {
- offset: 396,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_IMAGE_TIMESTAMP: ManifestField = ManifestField {
- offset: 400,
- size_bytes: 8,
-};
-
-pub const ROM_EXT_SIGNATURE_KEY_PUBLIC_EXPONENT: ManifestField =
- ManifestField {
- offset: 408,
- size_bytes: 4,
- };
-
-pub const ROM_EXT_USAGE_CONSTRAINTS: ManifestField = ManifestField {
- offset: 416,
- size_bytes: 32,
-};
-
-pub const ROM_EXT_PERIPHERAL_LOCKDOWN_INFO: ManifestField = ManifestField {
- offset: 448,
- size_bytes: 16,
-};
-
-pub const ROM_EXT_SIGNATURE_KEY_MODULUS: ManifestField = ManifestField {
- offset: 464,
- size_bytes: 384,
-};
-
-pub const ROM_EXT_EXTENSION0_OFFSET: ManifestField = ManifestField {
- offset: 848,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_EXTENSION0_CHECKSUM: ManifestField = ManifestField {
- offset: 852,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_EXTENSION1_OFFSET: ManifestField = ManifestField {
- offset: 856,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_EXTENSION1_CHECKSUM: ManifestField = ManifestField {
- offset: 860,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_EXTENSION2_OFFSET: ManifestField = ManifestField {
- offset: 864,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_EXTENSION2_CHECKSUM: ManifestField = ManifestField {
- offset: 868,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_EXTENSION3_OFFSET: ManifestField = ManifestField {
- offset: 872,
- size_bytes: 4,
-};
-
-pub const ROM_EXT_EXTENSION3_CHECKSUM: ManifestField = ManifestField {
- offset: 876,
- size_bytes: 4,
-};
-
-/// Manifest offset signed_area_start from the base.
-pub const ROM_EXT_SIGNED_AREA_START_OFFSET: usize = 392;
-
-/// Manifest offset interrupt_vector from the base.
-pub const ROM_EXT_INTERRUPT_VECTOR_OFFSET: usize = 1024;
-
-/// Manifest offset entry_point from the base.
-pub const ROM_EXT_ENTRY_POINT_OFFSET: usize = 1152;
+/// Checks the layout of the manifest struct.
+///
+/// Implemented as a function because using `offset_of!` at compile-time
+/// requires a nightly compiler.
+/// TODO(#6915): Convert this to a unit test after we start running rust tests during our builds.
+pub fn check_manifest_layout() {
+ assert_eq!(offset_of!(Manifest, identifier), 0);
+ assert_eq!(offset_of!(Manifest, reserved0), 4);
+ assert_eq!(offset_of!(Manifest, signature), 8);
+ assert_eq!(offset_of!(Manifest, image_length), 392);
+ assert_eq!(offset_of!(Manifest, image_version), 396);
+ assert_eq!(offset_of!(Manifest, image_timestamp), 400);
+ assert_eq!(offset_of!(Manifest, exponent), 408);
+ assert_eq!(offset_of!(Manifest, reserved1), 412);
+ assert_eq!(offset_of!(Manifest, usage_constraints), 416);
+ assert_eq!(offset_of!(Manifest, lockdown_info), 448);
+ assert_eq!(offset_of!(Manifest, modulus), 464);
+ assert_eq!(offset_of!(Manifest, extension0_offset), 848);
+ assert_eq!(offset_of!(Manifest, extension0_checksum), 852);
+ assert_eq!(offset_of!(Manifest, extension1_offset), 856);
+ assert_eq!(offset_of!(Manifest, extension1_checksum), 860);
+ assert_eq!(offset_of!(Manifest, extension2_offset), 864);
+ assert_eq!(offset_of!(Manifest, extension2_checksum), 868);
+ assert_eq!(offset_of!(Manifest, extension3_offset), 872);
+ assert_eq!(size_of::<Manifest>(), MANIFEST_SIZE as usize);
+}
diff --git a/sw/host/rom_ext_image_tools/signer/src/main.rs b/sw/host/rom_ext_image_tools/signer/src/main.rs
index 5fd3f23..7982d7a 100644
--- a/sw/host/rom_ext_image_tools/signer/src/main.rs
+++ b/sw/host/rom_ext_image_tools/signer/src/main.rs
@@ -6,14 +6,11 @@
#![deny(unused)]
#![deny(unsafe_code)]
+use std::convert::TryFrom;
use std::env;
use std::fs;
-use std::path::Path;
+use std::mem::size_of;
use std::path::PathBuf;
-use std::convert::TryFrom;
-
-use rom_ext_image::image::Image;
-use rom_ext_image::manifest;
use mundane::hash::Sha256;
use mundane::public::rsa::RsaPkcs1v15;
@@ -26,6 +23,13 @@
use anyhow::Context;
use anyhow::Result;
+use zerocopy::AsBytes;
+
+use rom_ext_image::image::Image;
+use rom_ext_image::image::ManifestBuffer;
+use rom_ext_image::manifest;
+use rom_ext_image::manifest::Manifest;
+
// Type aliases for convenience.
type ImageSignature =
mundane::public::rsa::RsaSignature<B3072, RsaPkcs1v15, Sha256>;
@@ -52,8 +56,9 @@
}
}
+// FIXME: Keeping for now, can be removed if not used in opentitantool.
/// Parses an unsigned big-endian hex string into a little-endian byte vector.
-fn parse_hex_str(hex_str: &str) -> Result<Vec<u8>> {
+fn _parse_hex_str(hex_str: &str) -> Result<Vec<u8>> {
ensure!(
hex_str.starts_with("0x")
&& hex_str.len() > 2
@@ -71,84 +76,28 @@
/// Updates the manifest of an image.
// TODO: This function must use a public key.
-fn update_image_manifest(
- image: &mut Image,
- key: impl AsRef<Path>,
-) -> Result<()> {
- let key = fs::read(&key).with_context(|| {
- format!("Failed to read the key from `{}`.", key.as_ref().display())
- })?;
- let key =
- PrivateKey::parse_from_der(&key).context("Failed to parse the key.")?;
+fn update_image_manifest(image: &mut Image, key: &PrivateKey) -> Result<()> {
+ *image.manifest = Manifest {
+ identifier: 0x4552544f,
+ image_length: u32::try_from(image.bytes().len())?,
+ ..Default::default()
+ };
- image.set_manifest_field(
- &manifest::ROM_EXT_SIGNATURE_KEY_PUBLIC_EXPONENT,
- key.public_exponent_be().iter().rev().cloned(),
- )?;
- image.set_manifest_field(
- &manifest::ROM_EXT_SIGNATURE_KEY_MODULUS,
- key.public_modulus_be().iter().rev().cloned(),
- )?;
- image.set_manifest_field(
- &manifest::ROM_EXT_MANIFEST_IDENTIFIER,
- parse_hex_str("0x4552544f")?,
- )?;
-
- image.set_manifest_field(
- &manifest::ROM_EXT_IMAGE_VERSION,
- // TODO: Use into_iter once it's stabilized (for all usages in this file).
- std::array::IntoIter::new(0_u32.to_le_bytes()),
- )?;
-
- // TODO: Do we need these fields?
- let extensions = [
- (
- &manifest::ROM_EXT_EXTENSION0_OFFSET,
- &manifest::ROM_EXT_EXTENSION0_CHECKSUM,
- ),
- (
- &manifest::ROM_EXT_EXTENSION1_OFFSET,
- &manifest::ROM_EXT_EXTENSION1_CHECKSUM,
- ),
- (
- &manifest::ROM_EXT_EXTENSION2_OFFSET,
- &manifest::ROM_EXT_EXTENSION2_CHECKSUM,
- ),
- (
- &manifest::ROM_EXT_EXTENSION3_OFFSET,
- &manifest::ROM_EXT_EXTENSION3_CHECKSUM,
- ),
- ];
- for fields in &extensions {
- image.set_manifest_field(
- fields.0,
- std::array::IntoIter::new(0_u32.to_le_bytes()),
- )?;
- image.set_manifest_field(
- fields.1,
- std::array::IntoIter::new(0_u32.to_le_bytes()),
- )?;
+ let exponent_be = key.public_exponent_be();
+ let dest = image.manifest.exponent.as_bytes_mut().iter_mut();
+ let src = exponent_be.iter().rev().copied();
+ ensure!(dest.len() >= src.len(), "Unexpected exponent length.");
+ for (d, s) in Iterator::zip(dest, src) {
+ *d = s;
}
- image.set_manifest_field(
- &manifest::ROM_EXT_USAGE_CONSTRAINTS,
- std::array::IntoIter::new(
- [0; manifest::ROM_EXT_USAGE_CONSTRAINTS.size_bytes],
- ),
- )?;
- image.set_manifest_field(
- &manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO,
- std::array::IntoIter::new(
- [0; manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO.size_bytes],
- ),
- )?;
- image.set_manifest_field(
- &manifest::ROM_EXT_IMAGE_TIMESTAMP,
- std::array::IntoIter::new(0_u64.to_le_bytes()),
- )?;
- image.set_manifest_field(
- &manifest::ROM_EXT_IMAGE_LENGTH,
- std::array::IntoIter::new(u32::try_from(image.len())?.to_le_bytes()),
- )?;
+
+ let modulus_be = key.public_modulus_be();
+ let dest = image.manifest.modulus.as_bytes_mut().iter_mut();
+ let src = modulus_be.iter().rev().copied();
+ ensure!(dest.len() == src.len(), "Unexpected modulus length.");
+ for (d, s) in Iterator::zip(dest, src) {
+ *d = s;
+ }
Ok(())
}
@@ -156,43 +105,52 @@
/// Calculates the signature for the signed portion of an image.
fn calculate_image_signature(
image: &Image,
- key: impl AsRef<Path>,
+ private_key: &PrivateKey,
) -> Result<ImageSignature> {
- let key = fs::read(&key).with_context(|| {
- format!("Failed to read key from `{}`.", key.as_ref().display())
- })?;
- let key =
- PrivateKey::parse_from_der(&key).context("Failed to parse the key.")?;
- let sig = ImageSignature::sign(&key, image.signed_bytes())
- .context("Failed to sign the image.")?;
- Ok(sig)
+ ImageSignature::sign(&private_key, &image.signed_bytes())
+ .context("Failed to calculate image signature.")
}
/// Updates the signature of an image.
fn update_image_signature(
image: &mut Image,
- signature: ImageSignature,
+ sig: ImageSignature,
) -> Result<()> {
- image.set_manifest_field(
- &manifest::ROM_EXT_IMAGE_SIGNATURE,
- signature.bytes().iter().rev().cloned(),
- )?;
+ let dest = image.manifest.signature.as_bytes_mut().iter_mut();
+ let src = sig.bytes().iter().rev().copied();
+ ensure!(dest.len() == src.len(), "Unexpected signature length.");
+ for (d, s) in Iterator::zip(dest, src) {
+ *d = s;
+ }
Ok(())
}
fn main() -> Result<()> {
+ // TODO(#6915): Convert this to a unit test after we start running rust tests during our
+ // builds.
+ manifest::check_manifest_layout();
let args = Args::new(env::args_os())?;
- let mut image = Image::from(fs::read(&args.input).with_context(|| {
- format!("Failed to read the image from {}", args.input.display())
- })?);
- // TODO for a future refactor into opentitantool: These functions probably should belong to a
- // Signer struct and should move into the image crate.
- // TODO: This must use the public key.
- update_image_manifest(&mut image, &args.priv_key)?;
- let sig = calculate_image_signature(&image, &args.priv_key)?;
+ // We use a separate buffer for manifest because it must have the same alignment as `Manifest`
+ // to be able to use `LayoutVerified::new()` and the approach we use to ensure this requires
+ // its size to be known at compile time.
+ let payload = &fs::read(&args.input)
+ .with_context(|| format!("Failed to read {}", args.input.display()))?
+ [size_of::<Manifest>()..];
+ let mut manifest_buffer = ManifestBuffer::new();
+ let mut image = Image::new(&mut manifest_buffer, payload)?;
+
+ let key = fs::read(&args.priv_key).with_context(|| {
+ format!("Failed to read the key from `{}`.", args.priv_key.display())
+ })?;
+ let key =
+ PrivateKey::parse_from_der(&key).context("Failed to parse the key.")?;
+ update_image_manifest(&mut image, &key)?;
+
+ let sig = calculate_image_signature(&image, &key)?;
update_image_signature(&mut image, sig)?;
- fs::write(&args.output, image).with_context(|| {
+
+ fs::write(&args.output, image.bytes()).with_context(|| {
format!("Failed to write the image to {}", args.output.display())
})?;
Ok(())