-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #29 from Foundation-Devices/jeandudey/sft-3538-add…
…-foundation-firmware-crate-to-parse-firmware-images SFT-3538: Add firmware image parser.
- Loading branch information
Showing
10 changed files
with
920 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,3 +12,6 @@ target/ | |
|
||
# CMake | ||
**/cmake-build-debug | ||
|
||
# Firmware files. | ||
*.bin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# SPDX-FileCopyrightText: © 2024 Foundation Devices, Inc. <[email protected]> | ||
# SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
[package] | ||
name = "foundation-firmware" | ||
version = "0.1.0" | ||
description = "Firmware image format" | ||
homepage.workspace = true | ||
edition = "2021" | ||
license = "GPL-3.0-or-later AND GPL-3.0-only" | ||
|
||
[[bin]] | ||
name = "foundation-firmware" | ||
required-features = ["binary"] | ||
|
||
[features] | ||
default = ["std", "binary"] | ||
std = ["hex?/std", "nom/std", "secp256k1/std"] | ||
binary = ["anyhow", "hex", "secp256k1/global-context", "std"] | ||
|
||
[dependencies] | ||
bitcoin_hashes = { workspace = true } | ||
heapless = { workspace = true } | ||
hex = { workspace = true, optional = true } | ||
nom = { workspace = true } | ||
secp256k1 = { workspace = true } | ||
anyhow = { workspace = true, optional = true } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// SPDX-FileCopyrightText: © 2024 Foundation Devices, Inc. <[email protected]> | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
|
||
use anyhow::{anyhow, bail, Context, Result}; | ||
use bitcoin_hashes::{sha256, sha256d, Hash, HashEngine}; | ||
use foundation_firmware::{header, verify_signature, Information, HEADER_LEN}; | ||
use nom::Finish; | ||
use secp256k1::global::SECP256K1; | ||
use std::fs; | ||
|
||
fn main() -> Result<()> { | ||
let file_name = std::env::args_os() | ||
.nth(1) | ||
.ok_or_else(|| anyhow!("provide a file name"))?; | ||
|
||
let file_buf = fs::read(file_name).context("failed to read firmware")?; | ||
|
||
let header_len = usize::try_from(HEADER_LEN).unwrap(); | ||
let header = match header(&file_buf[..header_len]).finish() { | ||
Ok((_, hdr)) => hdr, | ||
Err(_) => bail!("failed to parse firmware header"), | ||
}; | ||
|
||
header.verify().context("header verification failed")?; | ||
|
||
let file_hash = sha256::Hash::hash(&file_buf); | ||
let build_hash = sha256::Hash::hash(&file_buf[header_len..]); | ||
|
||
let mut engine = sha256d::Hash::engine(); | ||
engine.input(&header.information.serialize()); | ||
engine.input(&file_buf[header_len..]); | ||
let validation_hash = sha256d::Hash::from_engine(engine); | ||
|
||
// This one is just for debugging. | ||
let mut engine = sha256::Hash::engine(); | ||
engine.input(&header.information.serialize()); | ||
engine.input(&file_buf[header_len..]); | ||
let single_hash = sha256::Hash::from_engine(engine); | ||
|
||
let firmware_length = file_buf.len() - header_len; | ||
if firmware_length != usize::try_from(header.information.length).unwrap() { | ||
bail!( | ||
"invalid specified firmware length, on disk size is {}, specified one {}", | ||
firmware_length, | ||
header.information.length | ||
); | ||
} | ||
|
||
let signature1 = header.signature.signature1.serialize_compact(); | ||
let signature2 = header.signature.signature2.serialize_compact(); | ||
|
||
println!("Firmware:"); | ||
println!( | ||
"{:>17}: {:#08X} ({}) ", | ||
"Magic", | ||
header.information.magic, | ||
if header.information.magic == Information::MAGIC_COLOR { | ||
"color" | ||
} else { | ||
"mono" | ||
}, | ||
); | ||
println!("{:>17}: {}", "Timestamp", header.information.timestamp); | ||
println!("{:>17}: {}", "Date", header.information.date); | ||
println!("{:>17}: {}", "Version", header.information.version); | ||
println!("{:>17}: {} bytes", "Length", header.information.length); | ||
println!("{:>17}: {}", "Key", header.signature.public_key1); | ||
println!("{:>17}: {}", "Signature", hex::encode(signature1)); | ||
println!("{:>17}: {}", "Key", header.signature.public_key2); | ||
println!("{:>17}: {}", "Signature", hex::encode(signature2)); | ||
println!("{:>17}: {}", "File Hash", file_hash); | ||
println!("{:>17}: {}", "Build Hash", build_hash); | ||
println!( | ||
"{:>17}: {}", | ||
"Validation Hash", | ||
hex::encode(validation_hash.to_byte_array()) | ||
); | ||
println!( | ||
"{:>17}: {}", | ||
"Single Hash", | ||
hex::encode(single_hash.to_byte_array()) | ||
); | ||
println!(); | ||
|
||
verify_signature(&SECP256K1, &header, &validation_hash, None) | ||
.context("firmware signature verification failed.")?; | ||
|
||
println!("Firmware signature is valid!"); | ||
|
||
Ok(()) | ||
} |
Oops, something went wrong.