From 370b112087a60a09bec8ead2ae5d1c483f51efa7 Mon Sep 17 00:00:00 2001 From: Nicolas Stalder Date: Sat, 5 Mar 2022 20:02:57 +0100 Subject: [PATCH] Do a 0.1.0 release --- CHANGELOG.md | 13 ++++++ rustfmt.toml | 0 src/aid.rs | 51 ++++++++++++++--------- src/command.rs | 93 +++++++++++++++++++++++------------------- src/command/class.rs | 40 +++++++----------- src/lib.rs | 2 +- src/response/status.rs | 30 ++++++-------- 7 files changed, 126 insertions(+), 103 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 rustfmt.toml diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..50714c5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] - 2022-03-05 + +- use 2021 edition +- non-alpha release to bump dependees +- add an experimental CommandView diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..e69de29 diff --git a/src/aid.rs b/src/aid.rs index b31d752..3db51b8 100644 --- a/src/aid.rs +++ b/src/aid.rs @@ -39,18 +39,22 @@ pub enum Category { } impl core::fmt::Debug for Aid { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - if self.len <= self.truncated_len { - f.write_fmt(format_args!("'{} {}'", - hexstr!(&self.bytes[..5]), - hexstr!(&self.bytes[5..self.len as _]))) - } else { - f.write_fmt(format_args!("'{} {} {}'", - hexstr!(&self.bytes[..5]), - hexstr!(&self.bytes[5..self.truncated_len as _]), - hexstr!(&self.bytes[self.truncated_len as _..self.len as _]))) - } - } + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if self.len <= self.truncated_len { + f.write_fmt(format_args!( + "'{} {}'", + hexstr!(&self.bytes[..5]), + hexstr!(&self.bytes[5..self.len as _]) + )) + } else { + f.write_fmt(format_args!( + "'{} {} {}'", + hexstr!(&self.bytes[..5]), + hexstr!(&self.bytes[5..self.truncated_len as _]), + hexstr!(&self.bytes[self.truncated_len as _..self.len as _]) + )) + } + } } /// According to ISO 7816-4, "Application selection using AID as DF name": @@ -66,9 +70,9 @@ impl core::fmt::Debug for Aid { pub trait App { // using an associated constant here would make the trait object unsafe fn aid(&self) -> Aid; -// fn select_via_aid(&mut self, interface: Interface, aid: Aid) -> Result<()>; -// fn deselect(&mut self) -> Result<()>; -// fn call(&mut self, interface: Interface, command: &Command, response: &mut Response) -> Result<()>; + // fn select_via_aid(&mut self, interface: Interface, aid: Aid) -> Result<()>; + // fn deselect(&mut self) -> Result<()>; + // fn call(&mut self, interface: Interface, command: &Command, response: &mut Response) -> Result<()>; } impl core::ops::Deref for Aid { @@ -102,10 +106,20 @@ impl Aid { const_assert!(!aid.is_empty(), "AID needs at least a category identifier"); const_assert!(aid.len() <= Self::MAX_LEN, "AID too long"); const_assert!(truncated_len <= aid.len(), "truncated length too long"); - let mut s = Self { bytes: [0u8; Self::MAX_LEN], len: aid.len() as u8, truncated_len: truncated_len as u8 }; + let mut s = Self { + bytes: [0u8; Self::MAX_LEN], + len: aid.len() as u8, + truncated_len: truncated_len as u8, + }; s = s.fill(aid, 0); - const_assert!(!s.is_national() || aid.len() >= 5, "National RID must have length 5"); - const_assert!(!s.is_international() || aid.len() >= 5, "International RID must have length 5"); + const_assert!( + !s.is_national() || aid.len() >= 5, + "National RID must have length 5" + ); + const_assert!( + !s.is_international() || aid.len() >= 5, + "International RID must have length 5" + ); s } @@ -162,7 +176,6 @@ impl Aid { pub fn pix(&self) -> Option<&[u8]> { self.has_rid_pix().then(|| &self.bytes[5..]) } - } #[cfg(test)] diff --git a/src/command.rs b/src/command.rs index b3d1d5a..f8f0901 100644 --- a/src/command.rs +++ b/src/command.rs @@ -5,8 +5,7 @@ pub mod instruction; pub use instruction::Instruction; #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Command -{ +pub struct Command { class: class::Class, instruction: Instruction, @@ -23,8 +22,7 @@ pub struct Command #[derive(Clone, Debug, PartialEq, Eq)] /// Memory-efficient unowned version of [`Command`] -pub struct CommandView<'a> -{ +pub struct CommandView<'a> { class: class::Class, instruction: Instruction, @@ -74,8 +72,7 @@ impl<'a> CommandView<'a> { } } -impl Command -{ +impl Command { pub fn try_from(apdu: &[u8]) -> Result { apdu.try_into() } @@ -104,8 +101,10 @@ impl Command /// multiple APDU's into one. /// * Global Platform GPC_SPE_055 3.10 #[allow(clippy::result_unit_err)] - pub fn extend_from_command(&mut self, command: &Command) -> core::result::Result<(), ()> { - + pub fn extend_from_command( + &mut self, + command: &Command, + ) -> core::result::Result<(), ()> { // Always take the header from the last command; self.class = command.class(); self.instruction = command.instruction(); @@ -134,10 +133,9 @@ impl From for FromSliceError { } } -impl<'a> TryFrom<&'a[u8]> for CommandView<'a> -{ +impl<'a> TryFrom<&'a [u8]> for CommandView<'a> { type Error = FromSliceError; - fn try_from(apdu: &'a[u8]) -> core::result::Result { + fn try_from(apdu: &'a [u8]) -> core::result::Result { if apdu.len() < 4 { return Err(FromSliceError::TooShort); } @@ -153,7 +151,10 @@ impl<'a> TryFrom<&'a[u8]> for CommandView<'a> Ok(Self { // header - class, instruction, p1, p2, + class, + instruction, + p1, + p2, // maximum expected response length le: parsed.le, // payload @@ -165,10 +166,21 @@ impl<'a> TryFrom<&'a[u8]> for CommandView<'a> impl<'a> CommandView<'a> { pub fn to_owned(&self) -> Result, FromSliceError> { - let &CommandView { class, instruction, p1, p2, le, data, extended } = self; + let &CommandView { + class, + instruction, + p1, + p2, + le, + data, + extended, + } = self; Ok(Command { // header - class, instruction, p1, p2, + class, + instruction, + p1, + p2, // maximum expected response length le, // payload @@ -178,8 +190,7 @@ impl<'a> CommandView<'a> { } } -impl TryFrom<&[u8]> for Command -{ +impl TryFrom<&[u8]> for Command { type Error = FromSliceError; fn try_from(apdu: &[u8]) -> core::result::Result { let view: CommandView = apdu.try_into()?; @@ -209,7 +220,6 @@ fn replace_zero(value: usize, replacement: usize) -> usize { } #[inline] fn parse_lengths(body: &[u8]) -> Result { - // Encoding rules: // - Lc or Le = 0 => leave out // - short + extended length fields shall not be combined @@ -234,7 +244,7 @@ fn parse_lengths(body: &[u8]) -> Result { if l == 1 { parsed.lc = 0; parsed.le = replace_zero(b1, 256); - return Ok(parsed) + return Ok(parsed); } // Case 3S @@ -266,9 +276,7 @@ fn parse_lengths(body: &[u8]) -> Result { // Case 2E (no data) if l == 3 && b1 == 0 { parsed.lc = 0; - parsed.le = replace_zero( - u16::from_be_bytes([body[1], body[2]]) as usize, - 65_536); + parsed.le = replace_zero(u16::from_be_bytes([body[1], body[2]]) as usize, 65_536); return Ok(parsed); } @@ -283,9 +291,10 @@ fn parse_lengths(body: &[u8]) -> Result { // Case 4E if l == 5 + parsed.lc { - parsed.le = replace_zero( + parsed.le = replace_zero( u16::from_be_bytes([body[l - 2], body[l - 1]]) as usize, - 65_536); + 65_536, + ); parsed.offset = 3; return Ok(parsed); } @@ -304,25 +313,27 @@ mod test { #[test] fn command_chaining() { let apdu = &[ - 0x10, 0xdb, 0x3f, 0xff, 0xff, 0x5c, 0x03, 0x5f, 0xc1, 0x05, 0x53, 0x82, 0x01, 0x5b, 0x70, 0x82, - 0x01, 0x52, 0x30, 0x82, 0x01, 0x4e, 0x30, 0x81, 0xf5, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x11, - 0x00, 0x8b, 0xab, 0x31, 0xcf, 0x3e, 0xb9, 0xf5, 0x6a, 0x6f, 0x38, 0xf0, 0x5a, 0x4d, 0x7f, 0x55, - 0x62, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x2a, 0x31, - 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0d, 0x79, 0x75, 0x62, 0x69, 0x6b, 0x65, - 0x79, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, - 0x13, 0x07, 0x28, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, - 0x35, 0x31, 0x36, 0x30, 0x31, 0x31, 0x37, 0x32, 0x36, 0x5a, 0x18, 0x0f, 0x32, 0x30, 0x36, 0x32, - 0x30, 0x35, 0x31, 0x36, 0x30, 0x32, 0x31, 0x37, 0x32, 0x36, 0x5a, 0x30, 0x12, 0x31, 0x10, 0x30, - 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x07, 0x53, 0x53, 0x48, 0x20, 0x6b, 0x65, 0x79, 0x30, - 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, - 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x4f, 0x98, 0x63, 0x2f, 0x53, 0xbd, - 0xab, 0xee, 0xbf, 0x69, 0x73, 0x3a, 0x84, 0x0f, 0xfd, 0x9f, 0x9d, 0xb3, 0xce, 0x5c, 0x1e, 0x1b, - 0x84, 0x06, 0x63, 0x32, 0xff, 0x9c, 0x44, 0x0b, 0xce, 0x56, 0x13, 0x94, 0x00, 0x98, 0xe3, 0x46, - 0xc2, 0xbc, 0x3d, 0xe6, 0x5e, 0xf2, 0x81, 0x4b, 0xbc, 0xea, 0x2b, 0x9d, 0x47, 0xcc, 0x9b, 0x5e, - 0xbe, 0x1e, 0x2c, 0x69, 0x1d, 0xc3, 0x53, 0x4c, 0x89, 0x14, 0xa3, 0x12, 0x30, 0x10, 0x30, 0x0e, - 0x06, 0x03, 0x55, 0x1d, + 0x10, 0xdb, 0x3f, 0xff, 0xff, 0x5c, 0x03, 0x5f, 0xc1, 0x05, 0x53, 0x82, 0x01, 0x5b, + 0x70, 0x82, 0x01, 0x52, 0x30, 0x82, 0x01, 0x4e, 0x30, 0x81, 0xf5, 0xa0, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x11, 0x00, 0x8b, 0xab, 0x31, 0xcf, 0x3e, 0xb9, 0xf5, 0x6a, 0x6f, + 0x38, 0xf0, 0x5a, 0x4d, 0x7f, 0x55, 0x62, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x2a, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x0d, 0x79, 0x75, 0x62, 0x69, 0x6b, 0x65, 0x79, 0x2d, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x07, + 0x28, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x29, 0x30, 0x20, 0x17, 0x0d, 0x32, 0x30, 0x30, + 0x35, 0x31, 0x36, 0x30, 0x31, 0x31, 0x37, 0x32, 0x36, 0x5a, 0x18, 0x0f, 0x32, 0x30, + 0x36, 0x32, 0x30, 0x35, 0x31, 0x36, 0x30, 0x32, 0x31, 0x37, 0x32, 0x36, 0x5a, 0x30, + 0x12, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x07, 0x53, 0x53, + 0x48, 0x20, 0x6b, 0x65, 0x79, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, + 0x03, 0x42, 0x00, 0x04, 0x4f, 0x98, 0x63, 0x2f, 0x53, 0xbd, 0xab, 0xee, 0xbf, 0x69, + 0x73, 0x3a, 0x84, 0x0f, 0xfd, 0x9f, 0x9d, 0xb3, 0xce, 0x5c, 0x1e, 0x1b, 0x84, 0x06, + 0x63, 0x32, 0xff, 0x9c, 0x44, 0x0b, 0xce, 0x56, 0x13, 0x94, 0x00, 0x98, 0xe3, 0x46, + 0xc2, 0xbc, 0x3d, 0xe6, 0x5e, 0xf2, 0x81, 0x4b, 0xbc, 0xea, 0x2b, 0x9d, 0x47, 0xcc, + 0x9b, 0x5e, 0xbe, 0x1e, 0x2c, 0x69, 0x1d, 0xc3, 0x53, 0x4c, 0x89, 0x14, 0xa3, 0x12, + 0x30, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, ]; - let command = Command::<256>::try_from(apdu).unwrap(); + let _command = Command::<256>::try_from(apdu).unwrap(); } } diff --git a/src/command/class.rs b/src/command/class.rs index e0cef61..0e0228e 100644 --- a/src/command/class.rs +++ b/src/command/class.rs @@ -65,23 +65,19 @@ impl Class { pub fn secure_messaging(&self) -> SecureMessaging { match self.range { Range::Interindustry(which) => match which { - Interindustry::First => { - match (self.cla >> 2) & 0b11 { - 0b00 => SecureMessaging::None, - 0b01 => SecureMessaging::Proprietary, - 0b10 => SecureMessaging::Standard, - 0b11 => SecureMessaging::Authenticated, - _ => unreachable!(), - } + Interindustry::First => match (self.cla >> 2) & 0b11 { + 0b00 => SecureMessaging::None, + 0b01 => SecureMessaging::Proprietary, + 0b10 => SecureMessaging::Standard, + 0b11 => SecureMessaging::Authenticated, + _ => unreachable!(), + }, + Interindustry::Further => match (self.cla >> 5) != 0 { + true => SecureMessaging::Standard, + false => SecureMessaging::None, }, - Interindustry::Further => { - match (self.cla >> 5) != 0 { - true => SecureMessaging::Standard, - false => SecureMessaging::None, - } - } Interindustry::Reserved => SecureMessaging::Unknown, - } + }, _ => SecureMessaging::Unknown, } } @@ -98,17 +94,11 @@ impl Class { #[inline] pub fn channel(&self) -> Option { Some(match self.range() { - Range::Interindustry(Interindustry::First) => { - self.cla & 0b11 - } - Range::Interindustry(Interindustry::Further) => { - (4 + self.cla) & 0b111 - } - _ => return None + Range::Interindustry(Interindustry::First) => self.cla & 0b11, + Range::Interindustry(Interindustry::Further) => (4 + self.cla) & 0b111, + _ => return None, }) } - - } impl TryFrom for Class { @@ -150,7 +140,7 @@ impl TryFrom for Range { #[inline] fn try_from(cla: u8) -> Result { if cla == 0xff { - return Err(InvalidClass {}) + return Err(InvalidClass {}); } let range = match cla >> 5 { diff --git a/src/lib.rs b/src/lib.rs index 8139d0d..1c2b25c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ pub enum Interface { } pub type Data = heapless::Vec; -pub type Result = core::result::Result; +pub type Result = core::result::Result; pub mod aid; pub mod command; diff --git a/src/response/status.rs b/src/response/status.rs index eb0933a..c70bc83 100644 --- a/src/response/status.rs +++ b/src/response/status.rs @@ -10,20 +10,18 @@ impl Default for Status { #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Status { - -////////////////////////////// -// Normal processing (90, 61) -////////////////////////////// - + ////////////////////////////// + // Normal processing (90, 61) + ////////////////////////////// /// 9000 Success, /// 61XX MoreAvailable(u8), -/////////////////////////////// -// Warning processing (62, 63) -/////////////////////////////// + /////////////////////////////// + // Warning processing (62, 63) + /////////////////////////////// // 62XX: state of non-volatile memory unchanged (cf. SW2) @@ -31,9 +29,9 @@ pub enum Status { VerificationFailed, RemainingRetries(u8), -//////////////////////////////// -// Execution error (64, 65, 66) -//////////////////////////////// + //////////////////////////////// + // Execution error (64, 65, 66) + //////////////////////////////// // 64XX: persistent memory unchanged (cf. SW2) UnspecifiedNonpersistentExecutionError, @@ -43,9 +41,9 @@ pub enum Status { // 66XX: security related issues -/////////////////////////////// -// Checking error (67 - 6F) -/////////////////////////////// + /////////////////////////////// + // Checking error (67 - 6F) + /////////////////////////////// // 6700: wrong length, no further indication WrongLength, @@ -171,12 +169,10 @@ impl From for [u8; 2] { } } -impl From for Data -{ +impl From for Data { #[inline] fn from(status: Status) -> Data { let arr: [u8; 2] = status.into(); Data::from_slice(&arr).unwrap() } } -