From 9a41828bf8f184c7db356e7c7932acbbb9945781 Mon Sep 17 00:00:00 2001 From: Nicolas Stalder Date: Sat, 6 Nov 2021 20:34:00 +0100 Subject: [PATCH] Lints + cargo fmt --- .github/workflows/ci.yml | 6 +++- build.rs | 5 +-- src/apps.rs | 41 +++++++++++----------- src/apps/admin.rs | 20 +++++++---- src/apps/provisioner.rs | 2 +- src/bin/solo2/main.rs | 12 ++----- src/device_selection.rs | 41 ++++++++++++---------- src/lib.rs | 2 +- src/smartcard.rs | 73 ++++++++++++++++++---------------------- src/update.rs | 68 ++++++++++++++++++------------------- 10 files changed, 135 insertions(+), 135 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 051dcd9..279ef44 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,10 @@ jobs: rust: [stable] steps: + - name: Ubuntu dependencies + if: matrix.os == 'ubuntu-latest' + run: sudo apt-get update && sudo apt-get install -y libpcsclite-dev libudev-dev + - name: Checkout code uses: actions/checkout@v2 @@ -24,7 +28,7 @@ jobs: override: true components: rustfmt, clippy - - name: cargo build + - name: cargo build --locked uses: actions-rs/cargo@v1 with: command: build diff --git a/build.rs b/build.rs index ebccdf3..da87049 100644 --- a/build.rs +++ b/build.rs @@ -29,11 +29,12 @@ fn main() { // } // place side by side with binaries - let outdir = path::PathBuf::from(path::PathBuf::from(env_outdir).ancestors().skip(3).next().unwrap()); + let outdir = path::PathBuf::from(path::PathBuf::from(env_outdir).ancestors().nth(3).unwrap()); fs::create_dir_all(&outdir).unwrap(); println!("{:?}", &outdir); - #[cfg(feature = "cli")] { + #[cfg(feature = "cli")] + { use clap::Shell; // Use clap to build completion files. diff --git a/src/apps.rs b/src/apps.rs index 332b9c7..a154933 100644 --- a/src/apps.rs +++ b/src/apps.rs @@ -1,7 +1,7 @@ use hex_literal::hex; +use crate::device_selection::{prompt_user_to_select_device, Device}; use crate::{Card, Result}; -use crate::device_selection::{Device, prompt_user_to_select_device}; pub mod admin; pub mod ndef; @@ -10,20 +10,20 @@ pub mod piv; pub mod provisioner; pub mod tester; -pub const NFC_FORUM_RID: &'static [u8] = &hex!("D276000085"); -pub const NIST_RID: &'static [u8] = &hex!("A000000308"); -pub const SOLOKEYS_RID: &'static [u8] = &hex!("A000000847"); -pub const YUBICO_RID: &'static [u8] = &hex!("A000000527"); +pub const NFC_FORUM_RID: &[u8] = &hex!("D276000085"); +pub const NIST_RID: &[u8] = &hex!("A000000308"); +pub const SOLOKEYS_RID: &[u8] = &hex!("A000000847"); +pub const YUBICO_RID: &[u8] = &hex!("A000000527"); -pub const ADMIN_PIX: &'static [u8] = &hex!("00000001"); -pub const NDEF_PIX: &'static [u8] = &hex!("0101"); -pub const OATH_PIX: &'static [u8] = &hex!("2101"); +pub const ADMIN_PIX: &[u8] = &hex!("00000001"); +pub const NDEF_PIX: &[u8] = &hex!("0101"); +pub const OATH_PIX: &[u8] = &hex!("2101"); // the full PIX ends with 0100 for version 01.00, // truncated is enough to select -// pub const PIV_PIX: &'static [u8] = &hex!("000010000100"); -pub const PIV_PIX: &'static [u8] = &hex!("00001000"); -pub const PROVISIONER_PIX: &'static [u8] = &hex!("01000001"); -pub const TESTER_PIX: &'static [u8] = &hex!("01000000"); +// pub const PIV_PIX: &[u8] = &hex!("000010000100"); +pub const PIV_PIX: &[u8] = &hex!("00001000"); +pub const PROVISIONER_PIX: &[u8] = &hex!("01000001"); +pub const TESTER_PIX: &[u8] = &hex!("01000000"); pub trait App: Sized { const RID: &'static [u8]; @@ -53,11 +53,12 @@ pub trait App: Sized { fn card(&mut self) -> &mut Card; fn connect(uuid: Option<[u8; 16]>) -> Result { - let mut cards = Card::list(Default::default()); - if cards.len() == 0 { - return Err(anyhow::anyhow!("Could not find any Solo 2 devices connected.")); + if cards.is_empty() { + return Err(anyhow::anyhow!( + "Could not find any Solo 2 devices connected." + )); } if cards.len() > 1 { @@ -71,10 +72,11 @@ pub trait App: Sized { } } - return Err(anyhow::anyhow!("Could not find any Solo 2 device with uuid {}.", hex::encode(uuid))); - + return Err(anyhow::anyhow!( + "Could not find any Solo 2 device with uuid {}.", + hex::encode(uuid) + )); } else { - let mut devices: Vec = Default::default(); for card in cards { devices.push(card.into()) @@ -87,7 +89,6 @@ pub trait App: Sized { // Only one card, use it. Ok(cards.remove(0)) } - } fn new(uuid: Option<[u8; 16]>) -> Result; @@ -97,7 +98,7 @@ pub trait App: Sized { } fn call_with(&mut self, instruction: u8, data: &[u8]) -> Result> { - self.card().call(0, instruction, 0x00, 0x00, Some(&data)) + self.card().call(0, instruction, 0x00, 0x00, Some(data)) } fn print_aid() { diff --git a/src/apps/admin.rs b/src/apps/admin.rs index 3a65100..8740c0d 100644 --- a/src/apps/admin.rs +++ b/src/apps/admin.rs @@ -43,7 +43,7 @@ impl From for u32 { } impl fmt::Display for Version { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}.{}.{}", self.major, self.minor, self.patch) } } @@ -55,7 +55,11 @@ impl From<[u8; 4]> for Version { let minor = ((version >> 6) & ((1 << 16) - 1)) as _; let patch = (version & ((1 << 6) - 1)) as _; - Self { major, minor, patch } + Self { + major, + minor, + patch, + } } } @@ -84,15 +88,17 @@ impl App { bytes .try_into() .map_err(|_| anyhow::anyhow!("expected 16 byte UUID, got {}", &hex::encode(bytes))) - .map(|bytes| u128::from_be_bytes(bytes)) + .map(u128::from_be_bytes) } pub fn version(&mut self) -> Result { let version_bytes = self.call(Self::VERSION_COMMAND)?; - let bytes: [u8; 4] = version_bytes.as_slice() - .try_into() - .map_err(|_| anyhow::anyhow!("expected 4 bytes version, got {}", &hex::encode(version_bytes)))?; + let bytes: [u8; 4] = version_bytes.as_slice().try_into().map_err(|_| { + anyhow::anyhow!( + "expected 4 bytes version, got {}", + &hex::encode(version_bytes) + ) + })?; Ok(bytes.into()) - } } diff --git a/src/apps/provisioner.rs b/src/apps/provisioner.rs index 63252a4..211c9c2 100644 --- a/src/apps/provisioner.rs +++ b/src/apps/provisioner.rs @@ -99,7 +99,7 @@ impl App { bytes .try_into() .map_err(|_| anyhow::anyhow!("expected 16 byte UUID, got {}", &hex::encode(bytes))) - .map(|bytes| u128::from_be_bytes(bytes)) + .map(u128::from_be_bytes) } pub fn write_file(&mut self, data: &[u8], path: &str) -> Result<()> { diff --git a/src/bin/solo2/main.rs b/src/bin/solo2/main.rs index d0fc51d..d587760 100644 --- a/src/bin/solo2/main.rs +++ b/src/bin/solo2/main.rs @@ -3,13 +3,9 @@ extern crate log; mod cli; -// use core::convert::TryFrom; - use anyhow::anyhow; use lpc55::bootloader::Bootloader; -use solo2; - #[tokio::main] async fn main() { pretty_env_logger::init_custom_env("SOLO2_LOG"); @@ -24,7 +20,6 @@ async fn main() { } async fn try_main(args: clap::ArgMatches<'_>) -> anyhow::Result<()> { - let uuid_vec_maybe = args.value_of("uuid").map(|uuid| hex::decode(uuid).unwrap()); let uuid = if let Some(uuid_vec) = uuid_vec_maybe { if uuid_vec.len() != 16 { @@ -177,9 +172,7 @@ async fn try_main(args: clap::ArgMatches<'_>) -> anyhow::Result<()> { } if let Some(args) = args.subcommand_matches("store-t1-pubkey") { let pubkey_file = args.value_of("BYTES").unwrap(); - let public_key: [u8; 32] = std::fs::read(pubkey_file)? - .as_slice() - .try_into()?; + let public_key: [u8; 32] = std::fs::read(pubkey_file)?.as_slice().try_into()?; app.store_trussed_t1_intermediate_public_key(public_key)?; } if args.subcommand_matches("boot-to-bootrom").is_some() { @@ -193,7 +186,7 @@ async fn try_main(args: clap::ArgMatches<'_>) -> anyhow::Result<()> { let file = args.value_of("DATA").unwrap(); let data = std::fs::read(file)?; let path = args.value_of("PATH").unwrap(); - app.write_file(&data, &path)?; + app.write_file(&data, path)?; } } @@ -232,7 +225,6 @@ async fn try_main(args: clap::ArgMatches<'_>) -> anyhow::Result<()> { } if let Some(args) = args.subcommand_matches("bootloader") { - if args.subcommand_matches("reboot").is_some() { let bootloader = solo2::device_selection::find_bootloader(uuid)?; bootloader.reboot(); diff --git a/src/device_selection.rs b/src/device_selection.rs index fbc0104..0aafae6 100644 --- a/src/device_selection.rs +++ b/src/device_selection.rs @@ -3,7 +3,7 @@ use anyhow::anyhow; use lpc55::bootloader::Bootloader; -use crate::{Card}; +use crate::Card; pub enum Device { Card(Card), @@ -15,7 +15,9 @@ impl Device { /// Not guaranteed to work with other devices. pub fn uuid(&self) -> crate::Result { match self { - Device::Card(card) => card.uuid.ok_or(anyhow!("Device does not have a UUID")), + Device::Card(card) => card + .uuid + .ok_or_else(|| anyhow!("Device does not have a UUID")), Device::Bootloader(bootloader) => Ok(bootloader.uuid), } } @@ -50,8 +52,7 @@ impl From for Device { /// Return a specific bootloader that is connected. /// If no uuid is specified and there are multiple connected, the user will be prompted. pub fn find_bootloader(uuid: Option<[u8; 16]>) -> crate::Result { - let bootloaders = - Bootloader::list(); + let bootloaders = Bootloader::list(); if let Some(uuid) = uuid { let uuid_native = u128::from_be_bytes(uuid); @@ -60,9 +61,11 @@ pub fn find_bootloader(uuid: Option<[u8; 16]>) -> crate::Result { return Ok(bootloader); } } - return Err(anyhow!("Could not find any Solo 2 device with uuid {}.", hex::encode(uuid))); + return Err(anyhow!( + "Could not find any Solo 2 device with uuid {}.", + hex::encode(uuid) + )); } else { - let mut devices: Vec = Default::default(); for bootloader in bootloaders { devices.push(bootloader.into()) @@ -71,33 +74,35 @@ pub fn find_bootloader(uuid: Option<[u8; 16]>) -> crate::Result { let selected = prompt_user_to_select_device(devices)?; selected.bootloader() } - } - /// Have user select device from list of devices. pub fn prompt_user_to_select_device(mut devices: Vec) -> crate::Result { - use std::io::{stdin,stdout,Write}; + use std::io::{stdin, stdout, Write}; println!( -"Multiple devices connected. + "Multiple devices connected. Enter 0-{} to select: ", devices.len() ); - for i in 0 .. devices.len() { - match &devices[i] { + for (i, item) in devices.iter().enumerate() { + match item { Device::Bootloader(bootloader) => { println!( "{} - Bootloader UUID: {}", i, hex::encode(bootloader.uuid.to_be_bytes()) ); - - }, + } Device::Card(card) => { if let Some(uuid) = card.uuid { - println!("{} - \"{}\" UUID: {}", i, card.reader_name, hex::encode(uuid.to_be_bytes())); + println!( + "{} - \"{}\" UUID: {}", + i, + card.reader_name, + hex::encode(uuid.to_be_bytes()) + ); } else { println!("{} - \"{}\"", i, card.reader_name); } @@ -109,7 +114,9 @@ Enter 0-{} to select: ", stdout().flush().unwrap(); let mut input = String::new(); - stdin().read_line(&mut input).expect("Did not enter a correct string"); + stdin() + .read_line(&mut input) + .expect("Did not enter a correct string"); // remove whitespace input.retain(|c| !c.is_whitespace()); @@ -121,6 +128,4 @@ Enter 0-{} to select: ", } else { Ok(devices.remove(index)) } - } - diff --git a/src/lib.rs b/src/lib.rs index 1c0c8f5..c9b82a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,9 +2,9 @@ extern crate log; pub mod apps; -pub mod device_selection; #[cfg(feature = "dev-pki")] pub mod dev_pki; +pub mod device_selection; pub mod error; pub use error::{Error, Result}; pub mod smartcard; diff --git a/src/smartcard.rs b/src/smartcard.rs index c40b414..1be7f50 100644 --- a/src/smartcard.rs +++ b/src/smartcard.rs @@ -1,6 +1,6 @@ use anyhow::anyhow; -use core::convert::TryInto; use core::convert::TryFrom; +use core::convert::TryInto; use iso7816::Status; use pcsc::{Context, Protocols, Scope, ShareMode}; @@ -14,7 +14,9 @@ pub enum Filter { } impl Default for Filter { - fn default() -> Self { Filter::AllCards } + fn default() -> Self { + Filter::AllCards + } } pub struct Card { @@ -29,40 +31,37 @@ impl TryFrom<(&std::ffi::CStr, &Context)> for Card { let (reader, context) = pair; let mut card = context.connect(reader, ShareMode::Shared, Protocols::ANY)?; let uuid_maybe = Self::try_reading_uuid(&mut card) - .map(|uuid| u128::from_be_bytes(uuid)).ok(); - Ok(Self { card, reader_name: reader.to_str().unwrap().to_owned(), uuid: uuid_maybe }) + .map(u128::from_be_bytes) + .ok(); + Ok(Self { + card, + reader_name: reader.to_str().unwrap().to_owned(), + uuid: uuid_maybe, + }) } } impl Card { - pub fn list(filter: Filter) -> Vec { let cards = match Self::list_failable() { - Ok(cards) => { - cards - } - _ => { - Default::default() - } + Ok(cards) => cards, + _ => Default::default(), }; match filter { - Filter::AllCards => { - cards - }, - Filter::SoloCards => { - cards.into_iter().filter(|card| card.uuid.is_some()).collect() - } + Filter::AllCards => cards, + Filter::SoloCards => cards + .into_iter() + .filter(|card| card.uuid.is_some()) + .collect(), } } pub fn list_failable() -> crate::Result> { - let mut cards_with_trussed: Vec = Default::default(); let context = Context::establish(Scope::User)?; let l = context.list_readers_len()?; - let mut buffer = Vec::with_capacity(l); - buffer.resize(l, 0); + let mut buffer = vec![0; l]; let readers = context.list_readers(&mut buffer)?.collect::>(); @@ -75,10 +74,13 @@ impl Card { Ok(card) => { cards_with_trussed.push(card); debug!("Reader has a card."); - }, + } Err(_err) => { // Not a Trussed supported device. - info!("could not connect to card on reader, skipping ({:?}).", _err); + info!( + "could not connect to card on reader, skipping ({:?}).", + _err + ); } } } @@ -101,15 +103,9 @@ impl Card { Some(&aid), )?; - let uuid_bytes = Self::call_card( - card, - 0, - apps::admin::App::UUID_COMMAND, - 0x00, - 0x00, - None, - )?; - + let uuid_bytes = + Self::call_card(card, 0, apps::admin::App::UUID_COMMAND, 0x00, 0x00, None)?; + if uuid_bytes.len() == 16 { let mut uuid = [0u8; 16]; uuid.clone_from_slice(&uuid_bytes); @@ -131,8 +127,6 @@ impl Card { data: Option<&[u8]>, // ) -> iso7816::Result> { ) -> crate::Result> { - - let data = data.unwrap_or(&[]); let mut send_buffer = Vec::::with_capacity(data.len() + 16); @@ -152,18 +146,15 @@ impl Card { } send_buffer.extend_from_slice(data); } - if l <= 255 { - // Le = 256 - send_buffer.push(0); - } else { - send_buffer.push(0); + + send_buffer.push(0); + if l > 255 { send_buffer.push(0); } debug!(">> {}", hex::encode(&send_buffer)); - let mut recv_buffer = Vec::::with_capacity(3072); - recv_buffer.resize(3072, 0); + let mut recv_buffer = vec![0; 3072]; let l = card.transmit(&send_buffer, &mut recv_buffer)?.len(); debug!("RECV {} bytes", l); @@ -181,7 +172,7 @@ impl Card { let status = (sw1, sw2).try_into(); if Ok(Status::Success) != status { - return Err(if recv_buffer.len() > 0 { + return Err(if !recv_buffer.is_empty() { anyhow!( "card signaled error {:?} ({:X}, {:X}) with data {}", status, diff --git a/src/update.rs b/src/update.rs index 71a9d34..951fbf5 100644 --- a/src/update.rs +++ b/src/update.rs @@ -1,14 +1,13 @@ use std::{thread, time}; -use serde_json::{from_value, Value}; use anyhow::anyhow; use lpc55::bootloader::Bootloader; +use serde_json::{from_value, Value}; -use crate::{Card, smartcard}; -use crate::apps::App; use crate::apps::admin; -use crate::device_selection::{Device, prompt_user_to_select_device}; - +use crate::apps::App; +use crate::device_selection::{prompt_user_to_select_device, Device}; +use crate::{smartcard, Card}; pub async fn download_latest_solokeys_firmware() -> crate::Result> { println!("Downloading latest release from https://github.com/solokeys/solo2/"); @@ -21,8 +20,7 @@ pub async fn download_latest_solokeys_firmware() -> crate::Result> { .await? // .text() .json::() - .await? - ; + .await?; let tagname: String = from_value(resp["tag_name"].clone()).unwrap(); let assets: Vec = from_value(resp["assets"].clone()).unwrap(); @@ -30,21 +28,23 @@ pub async fn download_latest_solokeys_firmware() -> crate::Result> { let mut sbfile: Option> = None; let mut sha256hash: Option = None; - println!("Downloading firmware v{}...",tagname); + println!("Downloading firmware v{}...", tagname); for asset in assets { let asset_name: String = from_value(asset["name"].clone()).unwrap(); let asset_link: String = from_value(asset["browser_download_url"].clone()).unwrap(); if asset_name == format!("solo2-firmware-{}.sb2", tagname) { info!("found solo2 firmare in release"); - sbfile = Some(client - .get(asset_link.clone()) - .header("User-Agent", "solo2-cli") - .send() - .await? - .bytes() - .await?.to_vec()); - + sbfile = Some( + client + .get(asset_link.clone()) + .header("User-Agent", "solo2-cli") + .send() + .await? + .bytes() + .await? + .to_vec(), + ); } if asset_name == format!("solo2-firmware-{}.sha2", tagname) { info!("found solo2 firmare hash in release"); @@ -55,7 +55,7 @@ pub async fn download_latest_solokeys_firmware() -> crate::Result> { .await? .text() .await?; - sha256hash = Some(hashfile.split(" ").collect::>()[0].into()); + sha256hash = Some(hashfile.split(' ').collect::>()[0].into()); } } @@ -78,7 +78,7 @@ pub async fn download_latest_solokeys_firmware() -> crate::Result> { } // A rather tolerant update function, intended to be used by end users. -pub async fn run_update_procedure ( +pub async fn run_update_procedure( sbfile: Option, uuid: Option<[u8; 16]>, _skip_major_prompt: bool, @@ -104,10 +104,13 @@ pub async fn run_update_procedure ( if let Some(uuid) = uuid { for device in devices { if device.uuid().unwrap() == u128::from_be_bytes(uuid) { - return program_device(device, sbfile) + return program_device(device, sbfile); } } - return Err(anyhow!("Cannot find solo2 device with UUID {}", hex::encode(uuid))) + return Err(anyhow!( + "Cannot find solo2 device with UUID {}", + hex::encode(uuid) + )); } else if update_all { for device in devices { program_device(device, sbfile.clone())?; @@ -122,19 +125,17 @@ pub async fn run_update_procedure ( pub fn program_device(device: Device, sbfile: Vec) -> crate::Result<()> { let bootloader = match device { - Device::Bootloader(bootloader) => { - bootloader - }, + Device::Bootloader(bootloader) => bootloader, Device::Card(card) => { let uuid = card.uuid.unwrap(); let uuid = lpc55::uuid::Builder::from_bytes(uuid.to_be_bytes()).build(); - let mut admin = admin::App{ card }; + let mut admin = admin::App { card }; admin.select().ok(); let device_version: u32 = admin.version()?.into(); let sb2_product_version = - lpc55::secure_binary::Sb2Header::from_bytes(&sbfile.as_slice()[0 .. 96]) - .unwrap() - .product_version(); + lpc55::secure_binary::Sb2Header::from_bytes(&sbfile.as_slice()[0..96]) + .unwrap() + .product_version(); // Device stores version as: // major minor patch @@ -149,20 +150,20 @@ pub fn program_device(device: Device, sbfile: Vec) -> crate::Result<()> { println!("Check latest release notes here to double check: https://github.com/solokeys/solo2/releases"); println!("If you haven't used your key for anything yet, you can ignore this."); - println!(""); - println!("Continue? y/Y: "); + println!("\nContinue? y/Y: "); let mut input = String::new(); - stdin().read_line(&mut input).expect("Did not enter a correct string"); + stdin() + .read_line(&mut input) + .expect("Did not enter a correct string"); // remove whitespace input.retain(|c| !c.is_whitespace()); - if ["y","yes"].contains(&input.to_ascii_lowercase().as_str()) { + if ["y", "yes"].contains(&input.to_ascii_lowercase().as_str()) { println!("Continuing"); } else { return Err(anyhow!("User aborted.")); } - } admin.boot_to_bootrom().ok(); @@ -176,7 +177,7 @@ pub fn program_device(device: Device, sbfile: Vec) -> crate::Result<()> { let mut attempts: i32 = 10; while bootloader.is_err() && attempts > 0 { - info!("attempt {}", 11-attempts); + info!("attempt {}", 11 - attempts); thread::sleep(time::Duration::from_millis(100)); bootloader = Bootloader::try_find(None, None, Some(uuid)); attempts -= 1; @@ -195,4 +196,3 @@ pub fn program_device(device: Device, sbfile: Vec) -> crate::Result<()> { Ok(()) } -