Improve ROM_EXT image signer CLI and some cleanups
This change:
- Removes
- `config.hjson` along with related code and dependencies,
- `sw/host/rom_ext_image_tools/signer/dev` folder,
- Most of the methods from the image struct, essentially making it a
thin wrapper around a `Vec<[u8]>`,
- Exposes input image, private key, and output image paths as command
line arguments (required for signing an image with multiple keys during
build),
- Adds `thiserror` and `anyhow` dependencies to remove `expect`s,
- Modifies the ROM_EXT manifest generator rust template to generate
structs instead of individual constants, which enables some basic checks
in `Image::set_manifest_field`.
CLI is pretty basic because the functions in will eventually be
integrated into the opentitan tool.
Signed-off-by: Alphan Ulusoy <alphan@google.com>
diff --git a/sw/device/silicon_creator/rom_exts/manifest.rs.tpl b/sw/device/silicon_creator/rom_exts/manifest.rs.tpl
index 6b71f8e..34bd284 100644
--- a/sw/device/silicon_creator/rom_exts/manifest.rs.tpl
+++ b/sw/device/silicon_creator/rom_exts/manifest.rs.tpl
@@ -10,20 +10,21 @@
// --output-dir=<destination dir>
// --output-files=rust
+pub struct ManifestField {
+ pub offset: usize,
+ pub size_bytes: usize,
+}
+
% for name, region in regions:
-/// Manifest field ${name} offset from the base.
-pub const ${region.offset_name().as_c_define()}:u32 = ${region.base_addr};
-
-/// Manifest field ${name} size in bytes.
-pub const ${region.size_bytes_name().as_c_define()}:u32 = ${region.size_bytes};
-
-/// Manifest field ${name} size in words.
-pub const ${region.size_words_name().as_c_define()}:u32 = ${region.size_words};
+pub const ${region.name.as_c_define()}: ManifestField = ManifestField {
+ offset: ${region.base_addr},
+ size_bytes: ${region.size_bytes},
+};
% endfor
% for name, offset in offsets:
/// Manifest offset ${name} from the base.
-pub const ${offset.offset_name().as_c_define()}:u32 = ${offset.offset};
+pub const ${offset.offset_name().as_c_define()}:usize = ${offset.offset};
%endfor
diff --git a/sw/host/rom_ext_image_tools/signer/Cargo.lock b/sw/host/rom_ext_image_tools/signer/Cargo.lock
index 483c0b1..775f594 100644
--- a/sw/host/rom_ext_image_tools/signer/Cargo.lock
+++ b/sw/host/rom_ext_image_tools/signer/Cargo.lock
@@ -1,19 +1,10 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
-name = "aho-corasick"
-version = "0.7.15"
+name = "anyhow"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
[[package]]
name = "cfg-if"
@@ -33,28 +24,6 @@
]
[[package]]
-name = "lazy_static"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "linked-hash-map"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
-dependencies = [
- "serde",
- "serde_test",
-]
-
-[[package]]
name = "log"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -64,12 +33,6 @@
]
[[package]]
-name = "memchr"
-version = "2.3.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
-
-[[package]]
name = "mundane"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -79,24 +42,6 @@
]
[[package]]
-name = "num-traits"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
-dependencies = [
- "num-traits 0.2.14",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
name = "plain"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -112,10 +57,13 @@
]
[[package]]
-name = "quote"
-version = "0.3.15"
+name = "proc-macro2"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
+checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
+dependencies = [
+ "unicode-xid 0.2.2",
+]
[[package]]
name = "quote"
@@ -123,49 +71,31 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
dependencies = [
- "proc-macro2",
+ "proc-macro2 0.4.30",
]
[[package]]
-name = "regex"
-version = "1.4.2"
+name = "quote"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
- "thread_local",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
-
-[[package]]
-name = "rom_ext_config"
-version = "0.1.0"
-dependencies = [
- "serde",
- "serde-hjson",
- "serde_derive",
+ "proc-macro2 1.0.26",
]
[[package]]
name = "rom_ext_image"
version = "0.1.0"
dependencies = [
- "rom_ext_config",
+ "thiserror",
]
[[package]]
name = "rom_ext_signer"
version = "0.1.0"
dependencies = [
+ "anyhow",
"mundane",
- "rom_ext_config",
"rom_ext_image",
]
@@ -194,7 +124,7 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb"
dependencies = [
- "proc-macro2",
+ "proc-macro2 0.4.30",
"quote 0.6.13",
"syn 0.15.44",
]
@@ -215,100 +145,55 @@
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
-name = "serde"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
-
-[[package]]
-name = "serde-hjson"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153"
-dependencies = [
- "lazy_static 0.2.11",
- "linked-hash-map",
- "num-traits 0.1.43",
- "regex",
- "serde",
-]
-
-[[package]]
-name = "serde_codegen"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4c5d8a33087d8984f9535daa62a6498a08f6476050b00ab9339dd847e4c25cc"
-dependencies = [
- "quote 0.3.15",
- "serde_codegen_internals",
- "syn 0.10.8",
-]
-
-[[package]]
-name = "serde_codegen_internals"
-version = "0.11.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afad7924a009f859f380e4a2e3a509a845c2ac66435fcead74a4d983b21ae806"
-dependencies = [
- "syn 0.10.8",
-]
-
-[[package]]
-name = "serde_derive"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce44e5f4264b39e9d29c875357b7cc3ebdfb967bb9e22bfb5e44ffa400af5306"
-dependencies = [
- "serde_codegen",
-]
-
-[[package]]
-name = "serde_test"
-version = "0.8.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "syn"
-version = "0.10.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58fd09df59565db3399efbba34ba8a2fec1307511ebd245d0061ff9d42691673"
-dependencies = [
- "quote 0.3.15",
- "unicode-xid 0.0.4",
-]
-
-[[package]]
name = "syn"
version = "0.15.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
dependencies = [
- "proc-macro2",
+ "proc-macro2 0.4.30",
"quote 0.6.13",
"unicode-xid 0.1.0",
]
[[package]]
-name = "thread_local"
-version = "1.0.1"
+name = "syn"
+version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
dependencies = [
- "lazy_static 1.4.0",
+ "proc-macro2 1.0.26",
+ "quote 1.0.9",
+ "unicode-xid 0.2.2",
]
[[package]]
-name = "unicode-xid"
-version = "0.0.4"
+name = "thiserror"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
+checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
+dependencies = [
+ "proc-macro2 1.0.26",
+ "quote 1.0.9",
+ "syn 1.0.72",
+]
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
diff --git a/sw/host/rom_ext_image_tools/signer/Cargo.toml b/sw/host/rom_ext_image_tools/signer/Cargo.toml
index 9ed2af8..4aeeb3e 100644
--- a/sw/host/rom_ext_image_tools/signer/Cargo.toml
+++ b/sw/host/rom_ext_image_tools/signer/Cargo.toml
@@ -10,7 +10,6 @@
[workspace]
members = [
- "config",
"image"
]
@@ -25,8 +24,8 @@
debug = true
[dependencies]
-rom_ext_config = { path = "config" }
rom_ext_image = { path = "image" }
+anyhow = "1.0.40"
[dependencies.mundane]
version = "0.4.4"
diff --git a/sw/host/rom_ext_image_tools/signer/config/Cargo.toml b/sw/host/rom_ext_image_tools/signer/config/Cargo.toml
deleted file mode 100644
index 7e45593..0000000
--- a/sw/host/rom_ext_image_tools/signer/config/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-[package]
-name = "rom_ext_config"
-version = "0.1.0"
-authors = ["lowRISC contributors"]
-edition = "2018"
-
-[dependencies]
-serde = "0.8"
-serde_derive = "0.8"
-serde-hjson = "0.8"
diff --git a/sw/host/rom_ext_image_tools/signer/config/src/lib.rs b/sw/host/rom_ext_image_tools/signer/config/src/lib.rs
deleted file mode 100644
index c062489..0000000
--- a/sw/host/rom_ext_image_tools/signer/config/src/lib.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-pub mod parser;
diff --git a/sw/host/rom_ext_image_tools/signer/config/src/parser.rs b/sw/host/rom_ext_image_tools/signer/config/src/parser.rs
deleted file mode 100644
index c2cab1f..0000000
--- a/sw/host/rom_ext_image_tools/signer/config/src/parser.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-
-use std::fs;
-use std::path::Path;
-use std::path::PathBuf;
-
-use serde_derive::Deserialize;
-use serde_hjson::Value;
-
-/// Configuration used for the manifest initialisation.
-#[derive(Deserialize, Debug)]
-pub struct ParsedConfig {
- pub input_files: InputFiles,
- pub peripheral_lockdown_info: PeripheralLockdownInfo,
- pub manifest_identifier: String,
- pub image_version: String,
- pub extensions: [Extension; 4],
-}
-
-/// Input files that are required for signing.
-#[derive(Deserialize, Debug)]
-pub struct InputFiles {
- pub image_path: PathBuf,
- pub private_key_der_path: PathBuf,
- pub usage_constraints_path: PathBuf,
- pub system_state_value_path: PathBuf,
-}
-
-/// Peripheral Lockdown Information configuration data.
-///
-/// This data is used to produce 128-bit encoded manifest field.
-#[derive(Deserialize, Debug)]
-pub struct PeripheralLockdownInfo {
- pub value: u32,
-}
-
-/// ROM_EXT.
-#[derive(Deserialize, Debug)]
-pub struct Extension {
- pub offset: String,
- pub checksum: String,
-}
-
-impl ParsedConfig {
- pub fn new(config: &Path) -> Self {
- // Read the entire configuration file.
- let config_data = fs::read_to_string(config)
- .expect("Failed to read the config file!");
-
- let data: Value = serde_hjson::from_str(&config_data)
- .expect("Failed to parse the hjson config file!");
-
- let deserialized: ParsedConfig = serde_hjson::from_value(data)
- .expect("Failed to deserialize hjson config data!");
-
- deserialized
- }
-}
diff --git a/sw/host/rom_ext_image_tools/signer/dev/config.hjson b/sw/host/rom_ext_image_tools/signer/dev/config.hjson
deleted file mode 100644
index 17d25f7..0000000
--- a/sw/host/rom_ext_image_tools/signer/dev/config.hjson
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright lowRISC contributors.
-// Licensed under the Apache License, Version 2.0, see LICENSE for details.
-// SPDX-License-Identifier: Apache-2.0
-{
- input_files: {
- image_path: "sw/host/rom_ext_image_tools/signer/dev/rom_ext_blank_image.bin",
- private_key_der_path: "sw/host/rom_ext_image_tools/signer/dev/test_key_private.der",
- usage_constraints_path: "sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin",
- system_state_value_path: "sw/host/rom_ext_image_tools/signer/dev/system_state_value.bin",
- },
- // TBD
- peripheral_lockdown_info: {
- value: 0,
- },
- manifest_identifier: "43981",
- image_version: "0xdeadbeef",
- extensions: [
- {
- offset: "0xdeadbeef",
- checksum: "0xdeadbeef",
- },
- {
- offset: "0xdeadbeef",
- checksum: "0xdeadbeef",
- },
- {
- offset: "0xdeadbeef",
- checksum: "0xdeadbeef",
- },
- {
- offset: "0xdeadbeef",
- checksum: "0xdeadbeef",
- },
- ],
-}
diff --git a/sw/host/rom_ext_image_tools/signer/dev/rom_ext_blank_image.bin b/sw/host/rom_ext_image_tools/signer/dev/rom_ext_blank_image.bin
deleted file mode 100644
index 06d7405..0000000
--- a/sw/host/rom_ext_image_tools/signer/dev/rom_ext_blank_image.bin
+++ /dev/null
Binary files differ
diff --git a/sw/host/rom_ext_image_tools/signer/dev/system_state_value.bin b/sw/host/rom_ext_image_tools/signer/dev/system_state_value.bin
deleted file mode 100644
index 9648fd7..0000000
--- a/sw/host/rom_ext_image_tools/signer/dev/system_state_value.bin
+++ /dev/null
@@ -1 +0,0 @@
-¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
\ No newline at end of file
diff --git a/sw/host/rom_ext_image_tools/signer/dev/test_key_private.der b/sw/host/rom_ext_image_tools/signer/dev/test_key_private.der
deleted file mode 100644
index 184f3bc..0000000
--- a/sw/host/rom_ext_image_tools/signer/dev/test_key_private.der
+++ /dev/null
Binary files differ
diff --git a/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin b/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
deleted file mode 100644
index 9648fd7..0000000
--- a/sw/host/rom_ext_image_tools/signer/dev/usage_constraints.bin
+++ /dev/null
@@ -1 +0,0 @@
-¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
\ No newline at end of file
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 5810531..35cb230 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,4 @@
edition = "2018"
[dependencies]
-rom_ext_config = { path = "../config" }
\ No newline at end of file
+thiserror = "1.0.24"
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 ffec48c..2eac8ad 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,204 +6,67 @@
#![deny(unused)]
#![deny(unsafe_code)]
-use std;
-use std::ffi::OsString;
-use std::fs;
-use std::path::Path;
-use std::path::PathBuf;
-use std::time::SystemTime;
-use std::time::UNIX_EPOCH;
-
use crate::manifest;
-use rom_ext_config::parser::ParsedConfig;
-use rom_ext_config::parser::PeripheralLockdownInfo;
+use thiserror::Error;
-/// Stripped binary image buffer.
-pub struct RawImage {
+#[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,
+ },
+}
+
+/// A thin wrapper around a Vec to help with setting ROM_EXT manifest fields.
+#[derive(Debug)]
+pub struct Image {
data: Vec<u8>,
- path: PathBuf,
}
-/// Buffer manipulation API.
-impl RawImage {
- /// Creates the new image buffer.
- ///
- /// The data is read from the requested raw binary file.
- pub fn new(image_path: &Path) -> Self {
- let data = fs::read(image_path).expect("Failed to read the image!");
-
- RawImage {
- data: data,
- path: image_path.to_path_buf(),
- }
- }
-
- /// Updates the fields from the configuration file.
- ///
- /// This function updates the image manifest data with values parsed from
- /// the configuration file (known ahead of time). Some of the other fields
- /// like signature key public exponent and modulus, are obtained at
- /// run-time.
- pub fn update_static_fields(&mut self, config: &ParsedConfig) {
- // TODO: checks to make sure that the config values (strings) are not
- // bigger than the actual field size.
-
- let mut update = |value, offset| {
- let bytes = str_to_vec_u8(value);
- self.update_field(&bytes, offset);
- };
-
- update(
- &config.manifest_identifier,
- manifest::ROM_EXT_MANIFEST_IDENTIFIER_OFFSET,
- );
- update(
- &config.image_version,
- manifest::ROM_EXT_IMAGE_VERSION_OFFSET,
- );
-
- let offsets = [
- (
- manifest::ROM_EXT_EXTENSION0_OFFSET_OFFSET,
- manifest::ROM_EXT_EXTENSION0_CHECKSUM_OFFSET,
- ),
- (
- manifest::ROM_EXT_EXTENSION1_OFFSET_OFFSET,
- manifest::ROM_EXT_EXTENSION1_CHECKSUM_OFFSET,
- ),
- (
- manifest::ROM_EXT_EXTENSION2_OFFSET_OFFSET,
- manifest::ROM_EXT_EXTENSION2_CHECKSUM_OFFSET,
- ),
- (
- manifest::ROM_EXT_EXTENSION3_OFFSET_OFFSET,
- manifest::ROM_EXT_EXTENSION3_CHECKSUM_OFFSET,
- ),
- ];
- for (i, offset) in offsets.iter().enumerate() {
- update(&config.extensions[i].offset, offset.0);
- update(&config.extensions[i].checksum, offset.1);
- }
-
- let usage_constraints_path = &config.input_files.usage_constraints_path;
- self.update_usage_constraints_field(usage_constraints_path);
-
- let lockdown_info = &config.peripheral_lockdown_info;
- self.update_peripheral_lockdown_info_field(lockdown_info);
- }
-
- /// Updates ROM_EXT manifest timestamp field.
- ///
- /// The generated time stamp is u64. Normally time stamp is a signed
- /// integer, however there is no risk of overflow into a "negative".
- pub fn update_timestamp_field(&mut self) {
- let duration = SystemTime::now()
- .duration_since(UNIX_EPOCH)
- .expect("Failed to obtain the current time!");
-
- let bytes = duration.as_secs().to_le_bytes();
- self.update_field(&bytes, manifest::ROM_EXT_IMAGE_TIMESTAMP_OFFSET);
- }
-
- /// Updates ROM_EXT manifest signature key public exponent field.
- pub fn update_exponent_field(&mut self, exponent: &[u8]) {
- self.update_field(
- exponent,
- manifest::ROM_EXT_SIGNATURE_KEY_PUBLIC_EXPONENT_OFFSET,
- );
- }
-
- /// Updates ROM_EXT manifest signature key modulus field.
- pub fn update_modulus_field(&mut self, modulus: &[u8]) {
- self.update_field(
- modulus,
- manifest::ROM_EXT_SIGNATURE_KEY_MODULUS_OFFSET,
- );
- }
-
- /// Updates ROM_EXT manifest signature field.
- pub fn update_signature_field(&mut self, signature: &[u8]) {
- self.update_field(signature, manifest::ROM_EXT_IMAGE_SIGNATURE_OFFSET);
- }
-
- /// Returns the portion of the image used for signing.
- ///
- /// Manifest identifier and the signature itself are not signed. The rest
- /// of the image, including all the manifest fields that follow the
- /// signature field.
- pub fn data_to_sign(&self) -> &[u8] {
- let offset = manifest::ROM_EXT_SIGNED_AREA_START_OFFSET as usize;
- &self.data[offset..]
- }
-
- /// Writes the image buffer contents into a file.
- ///
- /// Places the new file alongside the original, with a "new_" prefix.
- pub fn write_file(&self) {
- let file_name =
- self.path.file_name().expect("Failed to get file stem!");
-
- let mut new_file_name = OsString::from("new_");
- new_file_name.push(file_name);
-
- let output_file = self.path.with_file_name(new_file_name);
-
- fs::write(output_file, &self.data)
- .expect("Failed to write the new binary file!");
- }
-
- /// Updates ROM_EXT manifest usage constraints field.
- fn update_usage_constraints_field(&mut self, path: &Path) {
- // Update fields from config.
- let usage_constraints =
- fs::read(path).expect("Failed to read usage constraints!");
- self.update_field(
- &usage_constraints,
- manifest::ROM_EXT_USAGE_CONSTRAINTS_OFFSET,
- );
- }
-
- /// Updates ROM_EXT manifest peripheral lockdown info field.
- ///
- /// The information is encoded into the 128-bit binary blob.
- fn update_peripheral_lockdown_info_field(
+impl Image {
+ /// Sets the value of a ROM_EXT manifest field.
+ pub fn set_manifest_field<I>(
&mut self,
- _info: &PeripheralLockdownInfo,
- ) {
- // TODO: generate the peripheral_lockdown_blob from
- // PeripheralLockdownInfo, meanwhile use a hard-coded vector.
-
- self.update_field(
- &[0xA5; 16],
- manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_OFFSET,
- );
+ 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(())
+ }
}
- /// Updates a ROM_EXT manifest field.
- ///
- /// Generic function, is used by the specific field update counterparts.
- fn update_field(&mut self, field_data: &[u8], field_offset: u32) {
- let begin = field_offset as usize;
- let end = begin + field_data.len();
- self.data.splice(begin..end, field_data.iter().cloned());
+ /// Returns the signed bytes of the image.
+ pub fn signed_bytes(&self) -> &[u8] {
+ &self.data[manifest::ROM_EXT_SIGNED_AREA_START_OFFSET..]
}
}
-fn str_to_u64(val: &str) -> u64 {
- match val.strip_prefix("0x") {
- Some(s) => u64::from_str_radix(s, 16),
- None => u64::from_str_radix(val, 10),
+impl AsRef<[u8]> for Image {
+ fn as_ref(&self) -> &[u8] {
+ &self.data
}
- .expect("Failed to parse string to u64!")
}
-/// Converts hex/decimal uint string into a little endian byte vector.
-///
-/// Note: only understands values up to u64::MAX.
-fn str_to_vec_u8(s: &str) -> Vec<u8> {
- match str_to_u64(s).to_le_bytes() {
- [a, b, c, d, 0, 0, 0, 0] => vec![a, b, c, d],
- bytes => bytes.to_vec(),
+impl From<Vec<u8>> for Image {
+ fn from(data: Vec<u8>) -> Self {
+ Image { data }
}
}
@@ -211,149 +74,45 @@
mod tests {
use super::*;
- use std::collections::HashMap;
- use std::env;
-
- use rom_ext_config::parser::Extension;
- use rom_ext_config::parser::InputFiles;
-
- static DEV_RELATIVE_PATH: &str = "sw/host/rom_ext_image_tools/signer/dev";
+ #[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
+ );
+ Ok(())
+ }
#[test]
- fn test_update_static_fields() {
- let source_root = env::var("MESON_SOURCE_ROOT")
- .expect("Failed, ENV variable not set!");
+ 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
+ })
+ );
+ }
- let dev_path = Path::new(&source_root).join(DEV_RELATIVE_PATH);
- let full_path = |path| dev_path.join(path);
-
- let config = ParsedConfig {
- input_files: InputFiles {
- image_path: full_path("rom_ext_blank_image.bin"),
- private_key_der_path: PathBuf::from(""),
- usage_constraints_path: full_path("usage_constraints.bin"),
- system_state_value_path: PathBuf::from(""),
- },
- peripheral_lockdown_info: PeripheralLockdownInfo { value: 0 },
- manifest_identifier: String::from("0x11111111"),
- image_version: String::from("0x22222222"),
- extensions: [
- Extension {
- offset: String::from("0x33333333"),
- checksum: String::from("0x44444444"),
- },
- Extension {
- offset: String::from("0x55555555"),
- checksum: String::from("0x55555555"),
- },
- Extension {
- offset: String::from("0x66666666"),
- checksum: String::from("0x66666666"),
- },
- Extension {
- offset: String::from("0x77777777"),
- checksum: String::from("0x77777777"),
- },
- ],
- };
-
- let mut test_items: HashMap<usize, Vec<u8>> = HashMap::new();
-
- let mut add_test_item = |key, val: Vec<u8>, expected_size| {
- assert_eq!(val.len(), expected_size as usize);
- test_items.insert(key as usize, val);
- };
-
- add_test_item(
- manifest::ROM_EXT_MANIFEST_IDENTIFIER_OFFSET,
- str_to_vec_u8(&config.manifest_identifier),
- manifest::ROM_EXT_MANIFEST_IDENTIFIER_SIZE_BYTES,
+ #[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
);
- add_test_item(
- manifest::ROM_EXT_IMAGE_VERSION_OFFSET,
- str_to_vec_u8(&config.image_version),
- manifest::ROM_EXT_IMAGE_VERSION_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION0_OFFSET_OFFSET,
- str_to_vec_u8(&config.extensions[0].offset),
- manifest::ROM_EXT_EXTENSION0_OFFSET_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION1_OFFSET_OFFSET,
- str_to_vec_u8(&config.extensions[1].offset),
- manifest::ROM_EXT_EXTENSION1_OFFSET_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION2_OFFSET_OFFSET,
- str_to_vec_u8(&config.extensions[2].offset),
- manifest::ROM_EXT_EXTENSION2_OFFSET_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION3_OFFSET_OFFSET,
- str_to_vec_u8(&config.extensions[3].offset),
- manifest::ROM_EXT_EXTENSION3_OFFSET_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION0_CHECKSUM_OFFSET,
- str_to_vec_u8(&config.extensions[0].checksum),
- manifest::ROM_EXT_EXTENSION0_CHECKSUM_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION1_CHECKSUM_OFFSET,
- str_to_vec_u8(&config.extensions[1].checksum),
- manifest::ROM_EXT_EXTENSION1_CHECKSUM_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION2_CHECKSUM_OFFSET,
- str_to_vec_u8(&config.extensions[2].checksum),
- manifest::ROM_EXT_EXTENSION2_CHECKSUM_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_EXTENSION3_CHECKSUM_OFFSET,
- str_to_vec_u8(&config.extensions[3].checksum),
- manifest::ROM_EXT_EXTENSION3_CHECKSUM_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_USAGE_CONSTRAINTS_OFFSET,
- fs::read(&config.input_files.usage_constraints_path)
- .expect("Failed to read usage constraints!"),
- manifest::ROM_EXT_USAGE_CONSTRAINTS_SIZE_BYTES,
- );
- add_test_item(
- manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_OFFSET,
- [0xA5; 16].to_vec(),
- manifest::ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_SIZE_BYTES,
- );
-
- let mut image = RawImage::new(&config.input_files.image_path);
-
- // Make sure that the image is blank to start with.
- assert_eq!(image.data, vec![0; image.data.len()]);
-
- image.update_static_fields(&config);
-
- // Iterate through every single byte in the image, if it belongs to a
- // field under test - compare with the respective `test_tuple` field,
- // otherwise it should be zero.
- let mut i = 0;
- while i < image.data.len() {
- // Check if the byte is part of the fields under test.
- match test_items.get(&i) {
- Some(x) => {
- // Check that field under test was successfully written
- // to the image.
- for byte in x {
- assert_eq!(*byte, image.data[i], "index = {}", i);
- i += 1;
- }
- }
- _ => {
- // Make sure that any other bytes are zero.
- assert_eq!(image.data[i], 0, "index = {}", i);
- i += 1;
- }
- }
- }
+ 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 5c6b473..2959964 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
@@ -10,164 +10,102 @@
// --output-dir=<destination dir>
// --output-files=rust
-/// Manifest field manifest_identifier offset from the base.
-pub const ROM_EXT_MANIFEST_IDENTIFIER_OFFSET: u32 = 0;
+pub struct ManifestField {
+ pub offset: usize,
+ pub size_bytes: usize,
+}
-/// Manifest field manifest_identifier size in bytes.
-pub const ROM_EXT_MANIFEST_IDENTIFIER_SIZE_BYTES: u32 = 4;
+pub const ROM_EXT_MANIFEST_IDENTIFIER: ManifestField = ManifestField {
+ offset: 0,
+ size_bytes: 4,
+};
-/// Manifest field manifest_identifier size in words.
-pub const ROM_EXT_MANIFEST_IDENTIFIER_SIZE_WORDS: u32 = 1;
+pub const ROM_EXT_IMAGE_SIGNATURE: ManifestField = ManifestField {
+ offset: 8,
+ size_bytes: 384,
+};
-/// Manifest field image_signature offset from the base.
-pub const ROM_EXT_IMAGE_SIGNATURE_OFFSET: u32 = 8;
+pub const ROM_EXT_IMAGE_LENGTH: ManifestField = ManifestField {
+ offset: 392,
+ size_bytes: 4,
+};
-/// Manifest field image_signature size in bytes.
-pub const ROM_EXT_IMAGE_SIGNATURE_SIZE_BYTES: u32 = 384;
+pub const ROM_EXT_IMAGE_VERSION: ManifestField = ManifestField {
+ offset: 396,
+ size_bytes: 4,
+};
-/// Manifest field image_signature size in words.
-pub const ROM_EXT_IMAGE_SIGNATURE_SIZE_WORDS: u32 = 96;
+pub const ROM_EXT_IMAGE_TIMESTAMP: ManifestField = ManifestField {
+ offset: 400,
+ size_bytes: 8,
+};
-/// Manifest field image_length offset from the base.
-pub const ROM_EXT_IMAGE_LENGTH_OFFSET: u32 = 392;
+pub const ROM_EXT_SIGNATURE_KEY_PUBLIC_EXPONENT: ManifestField =
+ ManifestField {
+ offset: 408,
+ size_bytes: 4,
+ };
-/// Manifest field image_length size in bytes.
-pub const ROM_EXT_IMAGE_LENGTH_SIZE_BYTES: u32 = 4;
+pub const ROM_EXT_USAGE_CONSTRAINTS: ManifestField = ManifestField {
+ offset: 416,
+ size_bytes: 32,
+};
-/// Manifest field image_length size in words.
-pub const ROM_EXT_IMAGE_LENGTH_SIZE_WORDS: u32 = 1;
+pub const ROM_EXT_PERIPHERAL_LOCKDOWN_INFO: ManifestField = ManifestField {
+ offset: 448,
+ size_bytes: 16,
+};
-/// Manifest field image_version offset from the base.
-pub const ROM_EXT_IMAGE_VERSION_OFFSET: u32 = 396;
+pub const ROM_EXT_SIGNATURE_KEY_MODULUS: ManifestField = ManifestField {
+ offset: 464,
+ size_bytes: 384,
+};
-/// Manifest field image_version size in bytes.
-pub const ROM_EXT_IMAGE_VERSION_SIZE_BYTES: u32 = 4;
+pub const ROM_EXT_EXTENSION0_OFFSET: ManifestField = ManifestField {
+ offset: 848,
+ size_bytes: 4,
+};
-/// Manifest field image_version size in words.
-pub const ROM_EXT_IMAGE_VERSION_SIZE_WORDS: u32 = 1;
+pub const ROM_EXT_EXTENSION0_CHECKSUM: ManifestField = ManifestField {
+ offset: 852,
+ size_bytes: 4,
+};
-/// Manifest field image_timestamp offset from the base.
-pub const ROM_EXT_IMAGE_TIMESTAMP_OFFSET: u32 = 400;
+pub const ROM_EXT_EXTENSION1_OFFSET: ManifestField = ManifestField {
+ offset: 856,
+ size_bytes: 4,
+};
-/// Manifest field image_timestamp size in bytes.
-pub const ROM_EXT_IMAGE_TIMESTAMP_SIZE_BYTES: u32 = 8;
+pub const ROM_EXT_EXTENSION1_CHECKSUM: ManifestField = ManifestField {
+ offset: 860,
+ size_bytes: 4,
+};
-/// Manifest field image_timestamp size in words.
-pub const ROM_EXT_IMAGE_TIMESTAMP_SIZE_WORDS: u32 = 2;
+pub const ROM_EXT_EXTENSION2_OFFSET: ManifestField = ManifestField {
+ offset: 864,
+ size_bytes: 4,
+};
-/// Manifest field signature_key_public_exponent offset from the base.
-pub const ROM_EXT_SIGNATURE_KEY_PUBLIC_EXPONENT_OFFSET: u32 = 408;
+pub const ROM_EXT_EXTENSION2_CHECKSUM: ManifestField = ManifestField {
+ offset: 868,
+ size_bytes: 4,
+};
-/// Manifest field signature_key_public_exponent size in bytes.
-pub const ROM_EXT_SIGNATURE_KEY_PUBLIC_EXPONENT_SIZE_BYTES: u32 = 4;
+pub const ROM_EXT_EXTENSION3_OFFSET: ManifestField = ManifestField {
+ offset: 872,
+ size_bytes: 4,
+};
-/// Manifest field signature_key_public_exponent size in words.
-pub const ROM_EXT_SIGNATURE_KEY_PUBLIC_EXPONENT_SIZE_WORDS: u32 = 1;
-
-/// Manifest field usage_constraints offset from the base.
-pub const ROM_EXT_USAGE_CONSTRAINTS_OFFSET: u32 = 416;
-
-/// Manifest field usage_constraints size in bytes.
-pub const ROM_EXT_USAGE_CONSTRAINTS_SIZE_BYTES: u32 = 32;
-
-/// Manifest field usage_constraints size in words.
-pub const ROM_EXT_USAGE_CONSTRAINTS_SIZE_WORDS: u32 = 8;
-
-/// Manifest field peripheral_lockdown_info offset from the base.
-pub const ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_OFFSET: u32 = 448;
-
-/// Manifest field peripheral_lockdown_info size in bytes.
-pub const ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_SIZE_BYTES: u32 = 16;
-
-/// Manifest field peripheral_lockdown_info size in words.
-pub const ROM_EXT_PERIPHERAL_LOCKDOWN_INFO_SIZE_WORDS: u32 = 4;
-
-/// Manifest field signature_key_modulus offset from the base.
-pub const ROM_EXT_SIGNATURE_KEY_MODULUS_OFFSET: u32 = 464;
-
-/// Manifest field signature_key_modulus size in bytes.
-pub const ROM_EXT_SIGNATURE_KEY_MODULUS_SIZE_BYTES: u32 = 384;
-
-/// Manifest field signature_key_modulus size in words.
-pub const ROM_EXT_SIGNATURE_KEY_MODULUS_SIZE_WORDS: u32 = 96;
-
-/// Manifest field extension0_offset offset from the base.
-pub const ROM_EXT_EXTENSION0_OFFSET_OFFSET: u32 = 848;
-
-/// Manifest field extension0_offset size in bytes.
-pub const ROM_EXT_EXTENSION0_OFFSET_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension0_offset size in words.
-pub const ROM_EXT_EXTENSION0_OFFSET_SIZE_WORDS: u32 = 1;
-
-/// Manifest field extension0_checksum offset from the base.
-pub const ROM_EXT_EXTENSION0_CHECKSUM_OFFSET: u32 = 852;
-
-/// Manifest field extension0_checksum size in bytes.
-pub const ROM_EXT_EXTENSION0_CHECKSUM_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension0_checksum size in words.
-pub const ROM_EXT_EXTENSION0_CHECKSUM_SIZE_WORDS: u32 = 1;
-
-/// Manifest field extension1_offset offset from the base.
-pub const ROM_EXT_EXTENSION1_OFFSET_OFFSET: u32 = 856;
-
-/// Manifest field extension1_offset size in bytes.
-pub const ROM_EXT_EXTENSION1_OFFSET_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension1_offset size in words.
-pub const ROM_EXT_EXTENSION1_OFFSET_SIZE_WORDS: u32 = 1;
-
-/// Manifest field extension1_checksum offset from the base.
-pub const ROM_EXT_EXTENSION1_CHECKSUM_OFFSET: u32 = 860;
-
-/// Manifest field extension1_checksum size in bytes.
-pub const ROM_EXT_EXTENSION1_CHECKSUM_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension1_checksum size in words.
-pub const ROM_EXT_EXTENSION1_CHECKSUM_SIZE_WORDS: u32 = 1;
-
-/// Manifest field extension2_offset offset from the base.
-pub const ROM_EXT_EXTENSION2_OFFSET_OFFSET: u32 = 864;
-
-/// Manifest field extension2_offset size in bytes.
-pub const ROM_EXT_EXTENSION2_OFFSET_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension2_offset size in words.
-pub const ROM_EXT_EXTENSION2_OFFSET_SIZE_WORDS: u32 = 1;
-
-/// Manifest field extension2_checksum offset from the base.
-pub const ROM_EXT_EXTENSION2_CHECKSUM_OFFSET: u32 = 868;
-
-/// Manifest field extension2_checksum size in bytes.
-pub const ROM_EXT_EXTENSION2_CHECKSUM_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension2_checksum size in words.
-pub const ROM_EXT_EXTENSION2_CHECKSUM_SIZE_WORDS: u32 = 1;
-
-/// Manifest field extension3_offset offset from the base.
-pub const ROM_EXT_EXTENSION3_OFFSET_OFFSET: u32 = 872;
-
-/// Manifest field extension3_offset size in bytes.
-pub const ROM_EXT_EXTENSION3_OFFSET_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension3_offset size in words.
-pub const ROM_EXT_EXTENSION3_OFFSET_SIZE_WORDS: u32 = 1;
-
-/// Manifest field extension3_checksum offset from the base.
-pub const ROM_EXT_EXTENSION3_CHECKSUM_OFFSET: u32 = 876;
-
-/// Manifest field extension3_checksum size in bytes.
-pub const ROM_EXT_EXTENSION3_CHECKSUM_SIZE_BYTES: u32 = 4;
-
-/// Manifest field extension3_checksum size in words.
-pub const ROM_EXT_EXTENSION3_CHECKSUM_SIZE_WORDS: u32 = 1;
+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: u32 = 392;
+pub const ROM_EXT_SIGNED_AREA_START_OFFSET: usize = 392;
/// Manifest offset interrupt_vector from the base.
-pub const ROM_EXT_INTERRUPT_VECTOR_OFFSET: u32 = 1024;
+pub const ROM_EXT_INTERRUPT_VECTOR_OFFSET: usize = 1024;
/// Manifest offset entry_point from the base.
-pub const ROM_EXT_ENTRY_POINT_OFFSET: u32 = 1152;
+pub const ROM_EXT_ENTRY_POINT_OFFSET: usize = 1152;
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 c760d89..023aa37 100644
--- a/sw/host/rom_ext_image_tools/signer/src/main.rs
+++ b/sw/host/rom_ext_image_tools/signer/src/main.rs
@@ -9,91 +9,186 @@
use std::env;
use std::fs;
use std::path::Path;
+use std::path::PathBuf;
-use rom_ext_config::parser::ParsedConfig;
-use rom_ext_image::image::RawImage;
+use rom_ext_image::image::Image;
+use rom_ext_image::manifest;
use mundane::hash::Sha256;
use mundane::public::rsa::RsaPkcs1v15;
-use mundane::public::rsa::RsaPrivKey;
-use mundane::public::rsa::RsaSignature;
use mundane::public::rsa::B3072;
use mundane::public::DerPrivateKey;
use mundane::public::Signature;
-fn main() {
- let arg: String = env::args().nth(1).expect("Config path is missing");
+use anyhow::bail;
+use anyhow::ensure;
+use anyhow::Context;
+use anyhow::Result;
- let config_path = Path::new(&arg);
+// Type aliases for convenience.
+type ImageSignature =
+ mundane::public::rsa::RsaSignature<B3072, RsaPkcs1v15, Sha256>;
+type PrivateKey = mundane::public::rsa::RsaPrivKey<B3072>;
- // Parse the config.
- let config = ParsedConfig::new(&config_path);
-
- // Read raw binary.
- let mut image = RawImage::new(&config.input_files.image_path);
-
- // Get the private key used for signature generation. It is also used to
- // extract key public exponent and modulus.
- let private_key_der = fs::read(&config.input_files.private_key_der_path)
- .expect("Failed to read the image!");
-
- // Update "signed" manifest fields.
- image.update_static_fields(&config);
-
- // Convert ASN.1 DER private key into Mundane RsaPrivKey.
- let private_key = RsaPrivKey::parse_from_der(&private_key_der)
- .expect("Failed to parse private key!");
-
- let mut exponent = private_key.public_exponent_be();
- // Encode public key components in little-endian byte order.
- exponent.reverse();
- image.update_exponent_field(&exponent);
-
- let mut modulus = private_key.public_modulus_be();
- // Encode public key components in little-endian byte order.
- modulus.reverse();
- image.update_modulus_field(&modulus);
-
- // Produce the signature from concatenated system_state_value,
- // device_usage_value and the portion of the "signed" portion of the image.
- image.update_timestamp_field();
- let image_sign_data = image.data_to_sign();
- let device_usage_value =
- &device_usage_value(&config.input_files.usage_constraints_path);
- let system_state_value =
- &system_state_value(&config.input_files.system_state_value_path);
-
- let mut message_to_sign = Vec::<u8>::new();
- message_to_sign.extend_from_slice(system_state_value);
- message_to_sign.extend_from_slice(device_usage_value);
- message_to_sign.extend_from_slice(image_sign_data);
-
- let signature = RsaSignature::<B3072, RsaPkcs1v15, Sha256>::sign(
- &private_key,
- &message_to_sign,
- )
- .expect("Failed to sign!");
-
- image.update_signature_field(&signature.bytes());
-
- // The whole image has been updated and signed, write the result to disk.
- image.write_file();
+// TODO: Remove this struct when this functionality is integrated into `opentitantool`.
+struct Args {
+ input: PathBuf,
+ priv_key: PathBuf,
+ output: PathBuf,
}
-/// Generates the device usage value.
-///
-/// This value is extrapolated from the ROM_EXT manifest usage_constraints
-/// field, and does not reside in the ROM_EXT manifest directly.
-pub fn device_usage_value(path: &Path) -> Vec<u8> {
- let _usage_constraints =
- fs::read(path).expect("Failed to read usage constraints!");
-
- // TODO: generate the device_usage_value from usage_constraints.
- // meanwhile use a "dummy" hard-coded vector.
- vec![0xA5; 1024]
+impl Args {
+ pub fn new(args: env::ArgsOs) -> Result<Args> {
+ let args = args.skip(1).collect::<Vec<_>>();
+ match args.as_slice() {
+ [input, priv_key, output] => Ok(Args {
+ input: PathBuf::from(input),
+ priv_key: PathBuf::from(priv_key),
+ output: PathBuf::from(output),
+ }),
+ args => bail!("Expected exactly 3 positional arguments: input, private key, and output, got: {}.", args.len()),
+ }
+ }
}
-/// Obtains the system state value from the binary on disk.
-pub fn system_state_value(path: &Path) -> Vec<u8> {
- fs::read(path).expect("Failed to read system state value!")
+/// Parses an unsigned big-endian hex string into a little-endian byte vector.
+fn parse_hex_str(hex_str: &str) -> Result<Vec<u8>> {
+ ensure!(
+ hex_str.starts_with("0x")
+ && hex_str.len() > 2
+ && hex_str.len() % 2 == 0,
+ "Invalid hex string: {}",
+ hex_str
+ );
+ let bytes = (2..hex_str.len())
+ .step_by(2)
+ .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16))
+ .rev()
+ .collect::<Result<_, _>>()?;
+ Ok(bytes)
+}
+
+/// 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.")?;
+
+ 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()),
+ )?;
+ }
+ 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()),
+ )?;
+
+ Ok(())
+}
+
+/// Calculates the signature for the signed portion of an image.
+fn calculate_image_signature(
+ image: &Image,
+ key: impl AsRef<Path>,
+) -> 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)
+}
+
+/// Updates the signature of an image.
+fn update_image_signature(
+ image: &mut Image,
+ signature: ImageSignature,
+) -> Result<()> {
+ image.set_manifest_field(
+ &manifest::ROM_EXT_IMAGE_SIGNATURE,
+ signature.bytes().iter().rev().cloned(),
+ )?;
+ Ok(())
+}
+
+fn main() -> Result<()> {
+ 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)?;
+ update_image_signature(&mut image, sig)?;
+ fs::write(&args.output, image).with_context(|| {
+ format!("Failed to write the image to {}", args.output.display())
+ })?;
+ Ok(())
}