Implement TryFrom (instead of offering that functionality without implementing the trait)

This commit is contained in:
Heiko Schaefer 2021-09-02 18:00:55 +02:00
parent b560d4eb5a
commit c7751ff4ce
5 changed files with 83 additions and 60 deletions

View file

@ -69,7 +69,7 @@ impl ApplicationRelatedData {
if let Some(eli) = eli { if let Some(eli) = eli {
// The card has returned extended length information // The card has returned extended length information
Ok(Some(ExtendedLengthInfo::from(&eli.serialize()[..])?)) Ok(Some((&eli.serialize()[..]).try_into()?))
} else { } else {
// The card didn't return this (optional) DO. That is ok. // The card didn't return this (optional) DO. That is ok.
Ok(None) Ok(None)
@ -117,7 +117,7 @@ impl ApplicationRelatedData {
let psb = self.0.find(&[0xc4].into()); let psb = self.0.find(&[0xc4].into());
if let Some(psb) = psb { if let Some(psb) = psb {
let pws = PWStatus::try_from(&psb.serialize())?; let pws = (&psb.serialize()[..]).try_into()?;
log::debug!("PW Status: {:x?}", pws); log::debug!("PW Status: {:x?}", pws);
@ -134,7 +134,7 @@ impl ApplicationRelatedData {
let fp = self.0.find(&[0xc5].into()); let fp = self.0.find(&[0xc5].into());
if let Some(fp) = fp { if let Some(fp) = fp {
let fp = fingerprint::to_keyset(&fp.serialize())?; let fp: KeySet<Fingerprint> = (&fp.serialize()[..]).try_into()?;
log::debug!("Fp: {:x?}", fp); log::debug!("Fp: {:x?}", fp);
@ -151,7 +151,8 @@ impl ApplicationRelatedData {
let kg = self.0.find(&[0xcd].into()); let kg = self.0.find(&[0xcd].into());
if let Some(kg) = kg { if let Some(kg) = kg {
let kg = key_generation_times::from(&kg.serialize())?; let kg: KeySet<KeyGenerationTime> =
(&kg.serialize()[..]).try_into()?;
log::debug!("Key generation: {:x?}", kg); log::debug!("Key generation: {:x?}", kg);

View file

@ -7,6 +7,7 @@ use anyhow::Result;
use nom::{bytes::complete::tag, number::complete as number, sequence}; use nom::{bytes::complete::tag, number::complete as number, sequence};
use crate::card_do::{complete, ExtendedLengthInfo}; use crate::card_do::{complete, ExtendedLengthInfo};
use std::convert::TryFrom;
fn parse(input: &[u8]) -> nom::IResult<&[u8], (u16, u16)> { fn parse(input: &[u8]) -> nom::IResult<&[u8], (u16, u16)> {
let (input, (_, cmd, _, resp)) = let (input, (_, cmd, _, resp)) =
@ -28,8 +29,12 @@ impl ExtendedLengthInfo {
pub fn max_response_bytes(&self) -> u16 { pub fn max_response_bytes(&self) -> u16 {
self.max_response_bytes self.max_response_bytes
} }
}
pub fn from(input: &[u8]) -> Result<Self> { impl TryFrom<&[u8]> for ExtendedLengthInfo {
type Error = anyhow::Error;
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
let eli = complete(parse(input))?; let eli = complete(parse(input))?;
Ok(Self { Ok(Self {

View file

@ -83,14 +83,21 @@ fn fingerprints(input: &[u8]) -> nom::IResult<&[u8], KeySet<Fingerprint>> {
) )
} }
/// Parse three fingerprints from the card into a KeySet of Fingerprints impl TryFrom<&[u8]> for KeySet<Fingerprint> {
pub(crate) fn to_keyset(input: &[u8]) -> Result<KeySet<Fingerprint>, Error> { type Error = Error;
log::trace!("Fingerprint from input: {:x?}, len {}", input, input.len());
// The input may be longer than 3 fingerprint, don't fail if it hasn't fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
// been completely consumed. log::trace!(
self::fingerprints(input) "Fingerprint from input: {:x?}, len {}",
.map(|res| res.1) input,
.map_err(|err| anyhow!("Parsing failed: {:?}", err)) input.len()
.map_err(Error::InternalError) );
// The input may be longer than 3 fingerprint, don't fail if it hasn't
// been completely consumed.
self::fingerprints(input)
.map(|res| res.1)
.map_err(|err| anyhow!("Parsing failed: {:?}", err))
.map_err(Error::InternalError)
}
} }

View file

@ -9,6 +9,7 @@ use nom::{combinator, number::complete as number, sequence};
use crate::card_do::{KeyGenerationTime, KeySet}; use crate::card_do::{KeyGenerationTime, KeySet};
use crate::Error; use crate::Error;
use std::convert::TryFrom;
impl From<KeyGenerationTime> for DateTime<Utc> { impl From<KeyGenerationTime> for DateTime<Utc> {
fn from(kg: KeyGenerationTime) -> Self { fn from(kg: KeyGenerationTime) -> Self {
@ -53,22 +54,26 @@ fn key_generation_set(
)))(input) )))(input)
} }
pub fn from(input: &[u8]) -> Result<KeySet<KeyGenerationTime>, Error> { impl TryFrom<&[u8]> for KeySet<KeyGenerationTime> {
// List of generation dates/times of key pairs, binary. type Error = Error;
// 4 bytes, Big Endian each for Sig, Dec and Aut. Each
// value shall be seconds since Jan 1, 1970. Default
// value is 00000000 (not specified).
log::trace!( fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
"Key generation times from input: {:x?}, len {}", // List of generation dates/times of key pairs, binary.
input, // 4 bytes, Big Endian each for Sig, Dec and Aut. Each
input.len() // value shall be seconds since Jan 1, 1970. Default
); // value is 00000000 (not specified).
// The input may be longer than 3 key generation times, don't fail if it log::trace!(
// hasn't been completely consumed. "Key generation times from input: {:x?}, len {}",
self::key_generation_set(input) input,
.map(|res| res.1) input.len()
.map_err(|err| anyhow!("Parsing failed: {:?}", err)) );
.map_err(Error::InternalError)
// The input may be longer than 3 key generation times, don't fail if it
// hasn't been completely consumed.
self::key_generation_set(input)
.map(|res| res.1)
.map_err(|err| anyhow!("Parsing failed: {:?}", err))
.map_err(Error::InternalError)
}
} }

View file

@ -7,9 +7,43 @@ use anyhow::anyhow;
use crate::card_do::PWStatus; use crate::card_do::PWStatus;
use crate::Error; use crate::Error;
use std::convert::TryFrom;
impl PWStatus { impl PWStatus {
pub fn try_from(input: &[u8]) -> Result<Self, Error> { /// PUT DO for PW Status Bytes accepts either 1 or 4 bytes of data.
/// This method generates the 1 byte version for 'long==false' and the
/// 4 bytes version for 'long==true'.
///
/// (See OpenPGP card spec, pg. 28)
pub(crate) fn serialize_for_put(&self, long: bool) -> Vec<u8> {
let mut data = vec![];
data.push(if !self.pw1_cds_multi { 0 } else { 1 });
if long {
let mut b2 = self.pw1_len;
if self.pw1_pin_block {
b2 |= 0x80;
}
data.push(b2);
data.push(self.rc_len);
let mut b4 = self.pw3_len;
if self.pw3_pin_block {
b4 |= 0x80;
}
data.push(b4);
}
data
}
}
impl TryFrom<&[u8]> for PWStatus {
type Error = Error;
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
if input.len() == 7 { if input.len() == 7 {
let pw1_cds_multi = input[0] == 0x01; let pw1_cds_multi = input[0] == 0x01;
let pw1_pin_block = input[1] & 0x80 != 0; let pw1_pin_block = input[1] & 0x80 != 0;
@ -39,33 +73,4 @@ impl PWStatus {
))) )))
} }
} }
/// PUT DO for PW Status Bytes accepts either 1 or 4 bytes of data.
/// This method generates the 1 byte version for 'long==false' and the
/// 4 bytes version for 'long==true'.
///
/// (See OpenPGP card spec, pg. 28)
pub fn serialize_for_put(&self, long: bool) -> Vec<u8> {
let mut data = vec![];
data.push(if !self.pw1_cds_multi { 0 } else { 1 });
if long {
let mut b2 = self.pw1_len;
if self.pw1_pin_block {
b2 |= 0x80;
}
data.push(b2);
data.push(self.rc_len);
let mut b4 = self.pw3_len;
if self.pw3_pin_block {
b4 |= 0x80;
}
data.push(b4);
}
data
}
} }