From eb15f477fac1872af4028ded403c511993ea2bed Mon Sep 17 00:00:00 2001 From: Ian McKenzie <13459320+ikmckenz@users.noreply.github.com> Date: Fri, 22 Mar 2024 02:18:40 -0700 Subject: [PATCH] Verify hashes of monero cli on download (#1572) * Bump Monero CLI for macos aarch64 to match other platforms * Check hash on download of monero cli * change panic to bail --------- Co-authored-by: Byron Hambly --- Cargo.lock | 1 + swap/Cargo.toml | 1 + swap/src/monero/wallet_rpc.rs | 32 +++++++++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index c7736aea..8c58895b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4290,6 +4290,7 @@ dependencies = [ "curve25519-dalek-ng", "data-encoding", "dialoguer", + "digest 0.10.7", "directories-next", "ecdsa_fun", "ed25519-dalek", diff --git a/swap/Cargo.toml b/swap/Cargo.toml index 3cb84995..8b60517a 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -25,6 +25,7 @@ conquer-once = "0.4" curve25519-dalek = { package = "curve25519-dalek-ng", version = "4" } data-encoding = "2.5" dialoguer = "0.11" +digest = "0.10.7" directories-next = "2" ecdsa_fun = { git = "https://github.com/LLFourn/secp256kfun", default-features = false, features = [ "libsecp_compat", "serde", "adaptor" ] } ed25519-dalek = "1" diff --git a/swap/src/monero/wallet_rpc.rs b/swap/src/monero/wallet_rpc.rs index e44d800e..e227c3f3 100644 --- a/swap/src/monero/wallet_rpc.rs +++ b/swap/src/monero/wallet_rpc.rs @@ -1,11 +1,13 @@ use ::monero::Network; use anyhow::{bail, Context, Error, Result}; use big_bytes::BigByte; +use data_encoding::HEXLOWER; use futures::{StreamExt, TryStreamExt}; use monero_rpc::wallet::{Client, MoneroWalletRpc as _}; use reqwest::header::CONTENT_LENGTH; use reqwest::Url; use serde::Deserialize; +use sha2::{Digest, Sha256}; use std::fmt; use std::fmt::{Debug, Display, Formatter}; use std::io::ErrorKind; @@ -45,19 +47,29 @@ compile_error!("unsupported operating system"); #[cfg(all(target_os = "macos", target_arch = "x86_64"))] const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-x64-v0.18.1.2.tar.bz2"; +#[cfg(all(target_os = "macos", target_arch = "x86_64"))] +const DOWNLOAD_HASH: &str = "ba1108c7a5e5efe15b6a628fb007c50f01c231f61137bba7427605286dbc6f01"; #[cfg(all(target_os = "macos", target_arch = "aarch64"))] -const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-armv8-v0.18.0.0.tar.bz2"; +const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-armv8-v0.18.1.2.tar.bz2"; +#[cfg(all(target_os = "macos", target_arch = "aarch64"))] +const DOWNLOAD_HASH: &str = "620b825c04f84845ed09de03b207a3230a34f74b30a8a07dde504a7d376ee4b9"; #[cfg(all(target_os = "linux", target_arch = "x86_64"))] const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.1.2.tar.bz2"; +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] +const DOWNLOAD_HASH: &str = "7d51e7072351f65d0c7909e745827cfd3b00abe5e7c4cc4c104a3c9b526da07e"; #[cfg(all(target_os = "linux", target_arch = "arm"))] const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-armv7-v0.18.1.2.tar.bz2"; +#[cfg(all(target_os = "linux", target_arch = "arm"))] +const DOWNLOAD_HASH: &str = "94ece435ed60f85904114643482c2b6716f74bf97040a7af237450574a9cf06d"; #[cfg(target_os = "windows")] const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-win-x64-v0.18.1.2.zip"; +#[cfg(target_os = "windows")] +const DOWNLOAD_HASH: &str = "0a3d4d1af7e094c05352c31b2dafcc6ccbc80edc195ca9eaedc919c36accd05a"; #[cfg(any(target_os = "macos", target_os = "linux"))] const PACKED_FILE: &str = "monero-wallet-rpc"; @@ -226,8 +238,14 @@ impl WalletRpc { DOWNLOAD_URL ); + let mut hasher = Sha256::new(); + let byte_stream = response .bytes_stream() + .map_ok(|bytes| { + hasher.update(&bytes); + bytes + }) .map_err(|err| std::io::Error::new(ErrorKind::Other, err)); #[cfg(not(target_os = "windows"))] @@ -256,6 +274,18 @@ impl WalletRpc { file.write_all(&bytes).await?; } + let result = hasher.finalize(); + let result_hash = HEXLOWER.encode(result.as_ref()); + if result_hash != DOWNLOAD_HASH { + bail!( + "SHA256 of download ({}) does not match expected ({})!", + result_hash, + DOWNLOAD_HASH + ); + } else { + tracing::debug!("Hashes match"); + } + file.flush().await?; tracing::debug!("Extracting archive");