Skip to content

Commit

Permalink
Add checksum verification to the CLI upgrade command
Browse files Browse the repository at this point in the history
  • Loading branch information
alfred-hodler committed Feb 4, 2024
1 parent c2fbb11 commit 355f563
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 7 deletions.
24 changes: 24 additions & 0 deletions coldcard-cli/src/fw_upgrade.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use coldcard::util;
use regex::Regex;
use semver::Version;

Expand Down Expand Up @@ -39,6 +40,7 @@ impl Release {
.collect();

found.sort_by(|a, b| a.version.cmp(&b.version));
found.dedup_by(|a, b| a.name == b.name);
found.reverse();

Ok(found)
Expand Down Expand Up @@ -74,6 +76,22 @@ impl Release {

Ok(bytes)
}

/// Verifies the checksum of the downloaded firmware release.
pub fn verify(&self, dl: &[u8]) -> Result<(), &'static str> {
let sigs = fetch_signatures().map_err(|_| "Cannot fetch signature file")?;
let line = sigs
.lines()
.find(|l| l.ends_with(&self.name))
.ok_or("Cannot find checksum")?;
let checksum = &line[0..64];

if checksum == hex::encode(util::sha256(dl)) {
Ok(())
} else {
Err("Checksum mismatch")
}
}
}

pub fn best_match<'a>(releases: &'a [Release], our_model: Option<&str>) -> Option<&'a Release> {
Expand All @@ -94,6 +112,12 @@ fn fetch_download_page() -> Result<String, ureq::Error> {
.map(|r| r.into_string().expect("bad utf-8"))
}

fn fetch_signatures() -> Result<String, ureq::Error> {
ureq::get("https://raw.githubusercontent.com/Coldcard/firmware/master/releases/signatures.txt")
.call()
.map(|r| r.into_string().expect("bad utf-8"))
}

fn firmware_regex() -> Regex {
Regex::new(r"[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]+-(v[0-9]+\.[0-9]+\.[0-9]+X?)(-mk.)?-coldcard.dfu")
.unwrap()
Expand Down
36 changes: 29 additions & 7 deletions coldcard-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,8 +558,8 @@ fn handle(cli: Cli) -> Result<(), Error> {

Command::Upgrade { path: Some(path) } => {
let firmware = firmware::Firmware::load_dfu(&path)?;
ProgressBar::new(1, 2, "📁 Load firmware").finish();
complete_upgrade(cc, firmware)?;
ProgressBar::new(1, 2, "📁 Read ").finish();
complete_upgrade(cc, firmware, 2)?;
}

Command::Upgrade { path: None } => {
Expand Down Expand Up @@ -681,9 +681,19 @@ fn handle(cli: Cli) -> Result<(), Error> {

pb.finish();

let pb = ProgressBar::new(2, 3, "🔒 Verify ");

match release.verify(&fw_bytes) {
Ok(_) => pb.finish(),
Err(err) => {
pb.finish_with_err(err);
return Ok(());
}
}

let firmware = firmware::Firmware::parse_dfu(&mut std::io::Cursor::new(fw_bytes))?;

complete_upgrade(cc, firmware)?;
complete_upgrade(cc, firmware, 3)?;
}

Command::User {
Expand Down Expand Up @@ -807,8 +817,12 @@ fn load_psbt(path: &PathBuf) -> Result<Vec<u8>, Error> {
}
}

fn complete_upgrade(mut cc: coldcard::Coldcard, firmware: firmware::Firmware) -> Result<(), Error> {
let pb = ProgressBar::new(2, 2, "💾 Flashing");
fn complete_upgrade(
mut cc: coldcard::Coldcard,
firmware: firmware::Firmware,
step: u16,
) -> Result<(), Error> {
let pb = ProgressBar::new(step, step, "💾 Flash ");
let size = firmware.bytes().len();

cc.upgrade(firmware, |uploaded, _| {
Expand All @@ -828,8 +842,8 @@ fn print_waiting() {
}

fn warn(text: &str) {
let warn = console::Style::new().color256(202).bold();
eprintln!("{} {}", warn.apply_to("WARNING:"), text);
let prefix = console::Style::new().color256(202).bold();
eprintln!("{} {}", prefix.apply_to("WARNING:"), text);
}

#[derive(Debug)]
Expand Down Expand Up @@ -938,6 +952,14 @@ impl ProgressBar {
.set_style(indicatif::ProgressStyle::with_template(FIN_TEMPLATE).unwrap());
self.pb.tick();
}

pub fn finish_with_err(self, err: &str) {
let err = format!("{{prefix:.bold}}: {} ❌", err);

self.pb
.set_style(indicatif::ProgressStyle::with_template(&err).unwrap());
self.pb.tick();
}
}

fn b64_encode(data: &[u8]) -> String {
Expand Down

0 comments on commit 355f563

Please sign in to comment.