From 3d3679d5b9a8c8cc90edb969c0f187740a3f2480 Mon Sep 17 00:00:00 2001 From: shimunn Date: Sat, 14 Sep 2019 01:04:56 +0200 Subject: [PATCH] implement hmac extension --- src/cbor.rs | 102 +++++++++++---------- src/crypto.rs | 63 +++++++------ src/error.rs | 6 +- src/extensions/hmac.rs | 200 +++++++++++++++++++++++++++++++++++++++++ src/extensions/mod.rs | 1 + src/hid_linux.rs | 14 +-- src/lib.rs | 71 ++++++++------- src/packet.rs | 28 +++--- 8 files changed, 350 insertions(+), 135 deletions(-) create mode 100644 src/extensions/hmac.rs create mode 100644 src/extensions/mod.rs diff --git a/src/cbor.rs b/src/cbor.rs index 434fadb..38d966f 100644 --- a/src/cbor.rs +++ b/src/cbor.rs @@ -4,11 +4,11 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use cbor_codec::{Config, Encoder, Decoder, GenericDecoder, GenericEncoder}; -use cbor_codec::value::Value; use cbor_codec::value; +use cbor_codec::value::Value; +use cbor_codec::{Config, Decoder, Encoder, GenericDecoder, GenericEncoder}; -use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian, ByteOrder}; +use byteorder::{BigEndian, ByteOrder, ReadBytesExt, WriteBytesExt}; use failure::ResultExt; use std::collections::HashMap; @@ -29,25 +29,23 @@ impl<'a> Request<'a> { match self { Request::MakeCredential(req) => req.encode(&mut encoder), Request::GetAssertion(req) => req.encode(&mut encoder), - Request::GetInfo => { - encoder - .writer() - .write_u8(0x04) - .context(FidoErrorKind::CborEncode) - .map_err(From::from) - } + Request::GetInfo => encoder + .writer() + .write_u8(0x04) + .context(FidoErrorKind::CborEncode) + .map_err(From::from), Request::ClientPin(req) => req.encode(&mut encoder), } } pub fn decode(&self, reader: R) -> FidoResult { Ok(match self { - Request::MakeCredential(_) => Response::MakeCredential( - MakeCredentialResponse::decode(reader)?, - ), - Request::GetAssertion(_) => Response::GetAssertion( - GetAssertionResponse::decode(reader)?, - ), + Request::MakeCredential(_) => { + Response::MakeCredential(MakeCredentialResponse::decode(reader)?) + } + Request::GetAssertion(_) => { + Response::GetAssertion(GetAssertionResponse::decode(reader)?) + } Request::GetInfo => Response::GetInfo(GetInfoResponse::decode(reader)?), Request::ClientPin(_) => Response::ClientPin(ClientPinResponse::decode(reader)?), }) @@ -77,9 +75,10 @@ pub struct MakeCredentialRequest<'a> { impl<'a> MakeCredentialRequest<'a> { pub fn encode(&self, mut encoder: &mut Encoder) -> FidoResult<()> { - encoder.writer().write_u8(0x01).context( - FidoErrorKind::CborEncode, - )?; // authenticatorMakeCredential + encoder + .writer() + .write_u8(0x01) + .context(FidoErrorKind::CborEncode)?; // authenticatorMakeCredential let mut length = 4; length += !self.exclude_list.is_empty() as usize; length += !self.extensions.is_empty() as usize; @@ -176,9 +175,10 @@ pub struct GetAssertionRequest<'a> { impl<'a> GetAssertionRequest<'a> { pub fn encode(&self, mut encoder: &mut Encoder) -> FidoResult<()> { - encoder.writer().write_u8(0x02).context( - FidoErrorKind::CborEncode, - )?; // authenticatorGetAssertion + encoder + .writer() + .write_u8(0x02) + .context(FidoErrorKind::CborEncode)?; // authenticatorGetAssertion let mut length = 2; length += !self.allow_list.is_empty() as usize; length += !self.extensions.is_empty() as usize; @@ -315,9 +315,10 @@ pub struct ClientPinRequest<'a> { impl<'a> ClientPinRequest<'a> { pub fn encode(&self, encoder: &mut Encoder) -> FidoResult<()> { - encoder.writer().write_u8(0x06).context( - FidoErrorKind::CborEncode, - )?; // authenticatorClientPIN + encoder + .writer() + .write_u8(0x06) + .context(FidoErrorKind::CborEncode)?; // authenticatorClientPIN let mut length = 2; length += self.key_agreement.is_some() as usize; length += self.pin_auth.is_some() as usize; @@ -383,7 +384,6 @@ impl ClientPinResponse { } } - #[derive(Debug)] pub struct OptionsInfo { pub plat: bool, @@ -439,21 +439,28 @@ impl AuthenticatorData { let flags = bytes[32]; data.up = (flags & 0x01) == 0x01; data.uv = (flags & 0x02) == 0x02; + let is_attested = (flags & 0x40) == 0x40; + let has_extension_data = (flags & 0x80) == 0x80; data.sign_count = BigEndian::read_u32(&bytes[33..37]); if bytes.len() < 38 { return Ok(data); } + let mut cur = Cursor::new(&bytes[37..]); - let attested_credential_data = AttestedCredentialData::from_bytes(&mut cur)?; - data.attested_credential_data = attested_credential_data; - if cur.position() >= (bytes.len() - 37) as u64 { - return Ok(data); + if is_attested { + let attested_credential_data = AttestedCredentialData::from_bytes(&mut cur)?; + data.attested_credential_data = attested_credential_data; + if cur.position() >= (bytes.len() - 37) as u64 { + return Ok(data); + } } - let mut decoder = GenericDecoder::new(Config::default(), cur); - for _ in 0..decoder.borrow_mut().object()? { - let key = decoder.borrow_mut().text()?; - let value = decoder.value()?; - data.extensions.insert(key.to_string(), value); + if has_extension_data { + let mut decoder = GenericDecoder::new(Config::default(), cur); + for _ in 0..decoder.borrow_mut().object()? { + let key = decoder.borrow_mut().text()?; + let value = decoder.value()?; + data.extensions.insert(key.to_string(), value); + } } Ok(data) } @@ -494,15 +501,15 @@ impl P256Key { if cose.key_type != 2 || cose.algorithm != -7 { Err(FidoErrorKind::KeyType)? } - if let (Some(Value::U8(curve)), - Some(Value::Bytes(value::Bytes::Bytes(x))), - Some(Value::Bytes(value::Bytes::Bytes(y)))) = - ( - cose.parameters.get(&-1), - cose.parameters.get(&-2), - cose.parameters.get(&-3), - ) - { + if let ( + Some(Value::U8(curve)), + Some(Value::Bytes(value::Bytes::Bytes(x))), + Some(Value::Bytes(value::Bytes::Bytes(y))), + ) = ( + cose.parameters.get(&-1), + cose.parameters.get(&-2), + cose.parameters.get(&-3), + ) { if *curve != 1 { Err(FidoErrorKind::KeyType)? } @@ -532,9 +539,10 @@ impl P256Key { (-1, Value::U8(1)), (-2, Value::Bytes(value::Bytes::Bytes(self.x.to_vec()))), (-3, Value::Bytes(value::Bytes::Bytes(self.y.to_vec()))), - ].iter() - .cloned() - .collect(), + ] + .iter() + .cloned() + .collect(), } } diff --git a/src/crypto.rs b/src/crypto.rs index 0e7ced1..1fa4902 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -4,15 +4,16 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use ring::{agreement, rand, digest, hmac, signature}; -use ring::error::Unspecified; -use untrusted::Input; -use rust_crypto::blockmodes::NoPadding; -use rust_crypto::aes; -use rust_crypto::buffer::{RefReadBuffer, RefWriteBuffer}; -use failure::ResultExt; use super::cbor::{CoseKey, P256Key}; use super::error::*; +use failure::ResultExt; +use ring::error::Unspecified; +use ring::{agreement, digest, hmac, rand, signature}; +use rust_crypto::aes; +use rust_crypto::blockmodes::NoPadding; +use rust_crypto::buffer::{RefReadBuffer, RefWriteBuffer}; +use rust_crypto::symmetriccipher::{Decryptor, Encryptor}; +use untrusted::Input; #[derive(Debug)] pub struct SharedSecret { @@ -26,9 +27,9 @@ impl SharedSecret { let private = agreement::EphemeralPrivateKey::generate(&agreement::ECDH_P256, &rng) .context(FidoErrorKind::GenerateKey)?; let public = &mut [0u8; agreement::PUBLIC_KEY_MAX_LEN][..private.public_key_len()]; - private.compute_public_key(public).context( - FidoErrorKind::GenerateKey, - )?; + private + .compute_public_key(public) + .context(FidoErrorKind::GenerateKey)?; let peer = P256Key::from_cose(peer_key) .context(FidoErrorKind::ParsePublic)? .bytes(); @@ -39,7 +40,8 @@ impl SharedSecret { peer, Unspecified, |material| Ok(digest::digest(&digest::SHA256, material)), - ).context(FidoErrorKind::GenerateSecret)?; + ) + .context(FidoErrorKind::GenerateSecret)?; let mut res = SharedSecret { public_key: P256Key::from_bytes(&public) .context(FidoErrorKind::ParsePublic)? @@ -50,42 +52,46 @@ impl SharedSecret { Ok(res) } - pub fn encrypt_pin(&self, pin: &str) -> FidoResult<[u8; 16]> { - let mut encryptor = aes::cbc_encryptor( + pub fn encryptor(&self) -> Box { + aes::cbc_encryptor( aes::KeySize::KeySize256, &self.shared_secret, &[0u8; 16], NoPadding, - ); + ) + } + + pub fn encrypt_pin(&self, pin: &str) -> FidoResult<[u8; 16]> { + let mut encryptor = self.encryptor(); let pin_bytes = pin.as_bytes(); let hash = digest::digest(&digest::SHA256, &pin_bytes); let in_bytes = &hash.as_ref()[0..16]; let mut input = RefReadBuffer::new(&in_bytes); let mut out_bytes = [0; 16]; let mut output = RefWriteBuffer::new(&mut out_bytes); - encryptor.encrypt(&mut input, &mut output, true).map_err( - |_| { - FidoErrorKind::EncryptPin - }, - )?; + encryptor + .encrypt(&mut input, &mut output, true) + .map_err(|_| FidoErrorKind::EncryptPin)?; Ok(out_bytes) } - pub fn decrypt_token(&self, data: &mut [u8]) -> FidoResult { - let mut decryptor = aes::cbc_decryptor( + pub fn decryptor(&self) -> Box { + aes::cbc_decryptor( aes::KeySize::KeySize256, &self.shared_secret, &[0u8; 16], NoPadding, - ); + ) + } + + pub fn decrypt_token(&self, data: &mut [u8]) -> FidoResult { + let mut decryptor = self.decryptor(); let mut input = RefReadBuffer::new(data); let mut out_bytes = [0; 16]; let mut output = RefWriteBuffer::new(&mut out_bytes); - decryptor.decrypt(&mut input, &mut output, true).map_err( - |_| { - FidoErrorKind::DecryptPin - }, - )?; + decryptor + .decrypt(&mut input, &mut output, true) + .map_err(|_| FidoErrorKind::DecryptPin)?; Ok(PinToken(hmac::SigningKey::new(&digest::SHA256, &out_bytes))) } } @@ -119,5 +125,6 @@ pub fn verify_signature( public_key, msg, signature, - ).is_ok() + ) + .is_ok() } diff --git a/src/error.rs b/src/error.rs index bb7b8f7..c1f5c74 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,11 +4,11 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use cbor_codec::{EncodeError, DecodeError}; +use cbor_codec::{DecodeError, EncodeError}; +use failure::{Backtrace, Context, Fail}; use std::fmt; use std::fmt::Display; -use failure::{Context, Backtrace, Fail}; pub type FidoResult = Result; @@ -52,7 +52,7 @@ pub enum FidoErrorKind { } impl Fail for FidoError { - fn cause(&self) -> Option<&Fail> { + fn cause(&self) -> Option<&dyn Fail> { self.0.cause() } diff --git a/src/extensions/hmac.rs b/src/extensions/hmac.rs new file mode 100644 index 0000000..96abd2d --- /dev/null +++ b/src/extensions/hmac.rs @@ -0,0 +1,200 @@ +use crate::cbor; +use crate::{FidoCredential, FidoDevice, FidoErrorKind, FidoResult}; +use cbor_codec::value::{Bytes, Int, Key, Text, Value}; +use cbor_codec::Encoder; +use cbor_codec::{Config, GenericDecoder}; +use rust_crypto::buffer::{RefReadBuffer, RefWriteBuffer}; +use rust_crypto::digest::Digest; +use rust_crypto::hmac::Hmac; +use rust_crypto::mac::Mac; +use rust_crypto::sha2::Sha256; +use std::collections::BTreeMap; +use std::io::Cursor; + +#[derive(Debug, Clone)] +pub struct FidoHmacCredential { + pub id: Vec, + pub rp_id: String, +} + +impl From for FidoHmacCredential { + fn from(cred: FidoCredential) -> Self { + FidoHmacCredential { + id: cred.id, + rp_id: cred.rp_id, + } + } +} + +pub trait HmacExtension { + fn extension_name() -> &'static str { + "hmac-secret" + } + + fn get_dict(&mut self, salt: &[u8; 32], salt2: Option<&[u8; 32]>) -> FidoResult { + let mut map = BTreeMap::new(); + map.insert( + Key::Text(Text::Text(Self::extension_name().to_owned())), + self.get_data(salt, salt2)?, + ); + Ok(Value::Map(map)) + } + + fn get_data(&mut self, salt: &[u8; 32], salt2: Option<&[u8; 32]>) -> FidoResult; + + fn make_hmac_credential(&mut self) -> FidoResult; + + fn get_hmac_assertion( + &mut self, + credential: &FidoHmacCredential, + salt: &[u8; 32], + salt2: Option<&[u8; 32]>, + ) -> FidoResult<([u8; 32], Option<[u8; 32]>)>; + + fn hmac_challange( + &mut self, + credential: &FidoHmacCredential, + input: &[u8], + ) -> FidoResult<[u8; 32]> { + let mut salt = [0u8; 32]; + let mut digest = Sha256::new(); + digest.input(input); + digest.result(&mut salt); + self.get_hmac_assertion(credential, &salt, None) + .map(|secret| secret.0) + } +} + +impl HmacExtension for FidoDevice { + fn get_data(&mut self, salt: &[u8; 32], salt2: Option<&[u8; 32]>) -> FidoResult { + let shared_secret = self.shared_secret.as_ref().unwrap(); + let mut encryptor = shared_secret.encryptor(); + let mut salt_enc = [0u8; 64]; + let mut output = RefWriteBuffer::new(&mut salt_enc); + let mut encrypt = || { + encryptor.encrypt(&mut RefReadBuffer::new(salt), &mut output, salt2.is_none())?; + if let Some(salt2) = salt2 { + encryptor + .encrypt(&mut RefReadBuffer::new(salt2), &mut output, true) + .map(|_| ()) + } else { + Ok(()) + } + }; + encrypt().map_err(|_| FidoErrorKind::Io)?; + + let key_agreement = || { + let mut cur = Cursor::new(Vec::new()); + let mut encoder = Encoder::new(&mut cur); + shared_secret.public_key.encode(&mut encoder).unwrap(); + cur.set_position(0); + let mut dec = GenericDecoder::new(Config::default(), cur); + dec.value() + }; + + let mut map = BTreeMap::new(); + map.insert( + Key::Int(Int::from_i64(0x01)), + key_agreement().map_err(|_| FidoErrorKind::Io)?, + ); + map.insert( + Key::Int(Int::from_i64(0x02)), + Value::Bytes(Bytes::Bytes( + salt_enc[0..((salt2.is_some() as usize + 1) * 32)].to_vec(), + )), + ); + + let mut salt_hmac = Hmac::new(Sha256::new(), &shared_secret.shared_secret); + salt_hmac.input(&salt_enc[0..((salt2.is_some() as usize + 1) * 32)]); + + let mut authed_salt_enc = [0u8; 32]; + authed_salt_enc.copy_from_slice(salt_hmac.result().code()); + + map.insert( + Key::Int(Int::from_i64(0x03)), + Value::Bytes(Bytes::Bytes(authed_salt_enc[0..16].to_vec())), + ); + + Ok(Value::Map(map)) + } + + fn make_hmac_credential(&mut self) -> FidoResult { + self.make_credential("hmac", &[0u8], "commandline", &[0u8; 32]) + .map(|cred| cred.into()) + } + + fn get_hmac_assertion( + &mut self, + credential: &FidoHmacCredential, + salt: &[u8; 32], + salt2: Option<&[u8; 32]>, + ) -> FidoResult<([u8; 32], Option<[u8; 32]>)> { + let client_data_hash = [0u8; 32]; + while self.shared_secret.is_none() { + self.init_shared_secret()?; + } + if self.needs_pin && self.pin_token.is_none() { + Err(FidoErrorKind::PinRequired)? + } + + if client_data_hash.len() != 32 { + Err(FidoErrorKind::CborEncode)? + } + let pin_auth = self + .pin_token + .as_ref() + .map(|token| token.auth(&client_data_hash)); + let ext_data: Value = self.get_data(salt, salt2)?; + let allow_list = [cbor::PublicKeyCredentialDescriptor { + cred_type: String::from("public-key"), + id: credential.id.clone(), + }]; + let request = cbor::GetAssertionRequest { + rp_id: &credential.rp_id, + client_data_hash: &client_data_hash, + allow_list: &allow_list, + extensions: &[(::extension_name(), &ext_data)], + options: Some(cbor::AuthenticatorOptions { + rk: false, + uv: true, + }), + pin_auth, + pin_protocol: pin_auth.and(Some(0x01)), + }; + let response = match self.cbor(cbor::Request::GetAssertion(request))? { + cbor::Response::GetAssertion(resp) => resp, + _ => Err(FidoErrorKind::CborDecode)?, + }; + let shared_secret = self.shared_secret.as_ref().unwrap(); + let mut decryptor = shared_secret.decryptor(); + let mut hmac_secret_combined = [0u8; 64]; + let _output = RefWriteBuffer::new(&mut hmac_secret_combined); + let hmac_secret_enc = match response + .auth_data + .extensions + .get(::extension_name()) + .ok_or(FidoErrorKind::CborDecode)? + { + Value::Bytes(hmac_ciphered) => Ok(match hmac_ciphered { + Bytes::Bytes(hmac_ciphered) => hmac_ciphered.to_vec(), + Bytes::Chunks(hmac_ciphered) => hmac_ciphered.iter().fold(Vec::new(), |s, i| { + let mut s = s; + s.extend_from_slice(&i); + s + }), + }), + _ => Err(FidoErrorKind::CborDecode), + }?; + let mut hmac_secret = ([0u8; 32], [0u8; 32]); + decryptor + .decrypt( + &mut RefReadBuffer::new(&hmac_secret_enc), + &mut RefWriteBuffer::new(unsafe { + std::mem::transmute::<_, &mut [u8; 64]>(&mut hmac_secret) + }), + true, + ) + .expect("failed to decrypt secret"); + Ok((hmac_secret.0, salt2.map(|_| hmac_secret.1))) + } +} diff --git a/src/extensions/mod.rs b/src/extensions/mod.rs new file mode 100644 index 0000000..c0f9333 --- /dev/null +++ b/src/extensions/mod.rs @@ -0,0 +1 @@ +pub mod hmac; diff --git a/src/hid_linux.rs b/src/hid_linux.rs index 0612cbd..ee819df 100644 --- a/src/hid_linux.rs +++ b/src/hid_linux.rs @@ -4,11 +4,11 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use std::io; -use std::fs; -use std::path::PathBuf; -use byteorder::{ByteOrder, LittleEndian}; pub use super::hid_common::*; +use byteorder::{ByteOrder, LittleEndian}; +use std::fs; +use std::io; +use std::path::PathBuf; static REPORT_DESCRIPTOR_KEY_MASK: u8 = 0xfc; static LONG_ITEM_ENCODING: u8 = 0xfe; @@ -18,9 +18,9 @@ static REPORT_SIZE: u8 = 0x74; pub fn enumerate() -> io::Result> { fs::read_dir("/sys/class/hidraw").map(|entries| { - entries.filter_map(|entry| entry.ok()).filter_map(|entry| { - path_to_device(&entry.path()).ok() - }) + entries + .filter_map(|entry| entry.ok()) + .filter_map(|entry| path_to_device(&entry.path()).ok()) }) } diff --git a/src/lib.rs b/src/lib.rs index 7be3529..1d7acd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,38 +37,39 @@ #![allow(dead_code)] -extern crate rand; extern crate failure; +extern crate rand; #[macro_use] extern crate failure_derive; #[macro_use] extern crate num_derive; -extern crate num_traits; extern crate byteorder; extern crate cbor as cbor_codec; +extern crate crypto as rust_crypto; +extern crate num_traits; extern crate ring; extern crate untrusted; -extern crate crypto as rust_crypto; -mod packet; +mod cbor; +mod crypto; +mod error; +pub mod extensions; mod hid_common; mod hid_linux; -mod error; -mod crypto; -mod cbor; +mod packet; use std::cmp; -use std::u8; -use std::u16; use std::fs; -use std::io::{Write, Cursor}; +use std::io::{Cursor, Write}; +use std::u16; +use std::u8; -use failure::{Fail, ResultExt}; -use rand::prelude::*; -use num_traits::FromPrimitive; +pub use self::error::*; use self::hid_linux as hid; use self::packet::CtapCommand; -pub use self::error::*; +use failure::{Fail, ResultExt}; +use num_traits::FromPrimitive; +use rand::prelude::*; static BROADCAST_CID: [u8; 4] = [0xff, 0xff, 0xff, 0xff]; @@ -76,9 +77,7 @@ static BROADCAST_CID: [u8; 4] = [0xff, 0xff, 0xff, 0xff]; pub fn get_devices() -> FidoResult> { hid::enumerate() .context(FidoErrorKind::Io) - .map(|devices| { - devices.filter(|dev| dev.usage_page == 0xf1d0 && dev.usage == 0x21) - }) + .map(|devices| devices.filter(|dev| dev.usage_page == 0xf1d0 && dev.usage == 0x21)) .map_err(From::from) } @@ -234,9 +233,10 @@ impl FidoDevice { if client_data_hash.len() != 32 { Err(FidoErrorKind::CborEncode)? } - let pin_auth = self.pin_token.as_ref().map( - |token| token.auth(&client_data_hash), - ); + let pin_auth = self + .pin_token + .as_ref() + .map(|token| token.auth(&client_data_hash)); let rp = cbor::PublicKeyCredentialRpEntity { id: rp_id, name: None, @@ -273,7 +273,7 @@ impl FidoDevice { .attested_credential_data .credential_public_key, )? - .bytes(); + .bytes(); Ok(FidoCredential { id: response.auth_data.attested_credential_data.credential_id, rp_id: String::from(rp_id), @@ -300,15 +300,14 @@ impl FidoDevice { if client_data_hash.len() != 32 { Err(FidoErrorKind::CborEncode)? } - let pin_auth = self.pin_token.as_ref().map( - |token| token.auth(&client_data_hash), - ); - let allow_list = [ - cbor::PublicKeyCredentialDescriptor { - cred_type: String::from("public-key"), - id: credential.id.clone(), - }, - ]; + let pin_auth = self + .pin_token + .as_ref() + .map(|token| token.auth(&client_data_hash)); + let allow_list = [cbor::PublicKeyCredentialDescriptor { + cred_type: String::from("public-key"), + id: credential.id.clone(), + }]; let request = cbor::GetAssertionRequest { rp_id: &credential.rp_id, client_data_hash: client_data_hash, @@ -335,7 +334,9 @@ impl FidoDevice { fn cbor(&mut self, request: cbor::Request) -> FidoResult { let mut buf = Cursor::new(Vec::new()); - request.encode(&mut buf).context(FidoErrorKind::CborEncode)?; + request + .encode(&mut buf) + .context(FidoErrorKind::CborEncode)?; let response = self.exchange(CtapCommand::Cbor, &buf.into_inner())?; request .decode(Cursor::new(response)) @@ -372,11 +373,9 @@ impl FidoDevice { while first_packet.is_none() { let packet = packet::InitPacket::from_reader(&mut self.device, 64)?; if packet.cmd == CtapCommand::Error { - Err( - packet::CtapError::from_u8(packet.payload[0]) - .unwrap_or(packet::CtapError::Other) - .context(FidoErrorKind::ParseCtap), - )? + Err(packet::CtapError::from_u8(packet.payload[0]) + .unwrap_or(packet::CtapError::Other) + .context(FidoErrorKind::ParseCtap))? } if packet.cid == self.channel_id && &packet.cmd == cmd { first_packet = Some(packet); diff --git a/src/packet.rs b/src/packet.rs index 943e12c..e7108e8 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -4,9 +4,9 @@ // http://apache.org/licenses/LICENSE-2.0> or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. -use num_traits::{FromPrimitive, ToPrimitive}; -use failure::ResultExt; use super::error::*; +use failure::ResultExt; +use num_traits::{FromPrimitive, ToPrimitive}; use std::io::{Read, Write}; @@ -81,9 +81,9 @@ pub fn write_init_packet( Err(FidoErrorKind::WritePacket)? } packet.resize(report_size + 1, 0); - writer.write_all(&packet).context( - FidoErrorKind::WritePacket, - )?; + writer + .write_all(&packet) + .context(FidoErrorKind::WritePacket)?; Ok(()) } @@ -98,9 +98,9 @@ impl InitPacket { pub fn from_reader(mut reader: R, report_size: usize) -> FidoResult { let mut buf = Vec::with_capacity(report_size); buf.resize(report_size, 0); - reader.read_exact(&mut buf[0..report_size]).context( - FidoErrorKind::ReadPacket, - )?; + reader + .read_exact(&mut buf[0..report_size]) + .context(FidoErrorKind::ReadPacket)?; let mut cid = [0; 4]; cid.copy_from_slice(&buf[0..4]); let cmd = match CtapCommand::from_u8(buf[4] ^ FRAME_INIT) { @@ -142,9 +142,9 @@ pub fn write_cont_packet( Err(FidoErrorKind::WritePacket)? } packet.resize(report_size + 1, 0); - writer.write_all(&packet).context( - FidoErrorKind::WritePacket, - )?; + writer + .write_all(&packet) + .context(FidoErrorKind::WritePacket)?; Ok(()) } @@ -162,9 +162,9 @@ impl ContPacket { ) -> FidoResult { let mut buf = Vec::with_capacity(report_size); buf.resize(report_size, 0); - reader.read_exact(&mut buf[0..report_size]).context( - FidoErrorKind::ReadPacket, - )?; + reader + .read_exact(&mut buf[0..report_size]) + .context(FidoErrorKind::ReadPacket)?; let mut cid = [0; 4]; cid.copy_from_slice(&buf[0..4]); let seq = buf[4];