Cleanup Tlv, Tag, Value:

- Make Tlv/Tag fields private.
- Rename TlvEntry to Value.
- impl TryFrom<&[u8]> for Tlv
This commit is contained in:
Heiko Schaefer 2021-08-28 18:02:08 +02:00
parent 821b5f0dae
commit c25c8b55b8
6 changed files with 153 additions and 146 deletions

View file

@ -17,7 +17,7 @@ use crate::crypto_data::{
CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial, CardUploadableKey, Cryptogram, EccType, Hash, PublicKeyMaterial,
}; };
use crate::errors::OpenpgpCardError; use crate::errors::OpenpgpCardError;
use crate::tlv::{tag::Tag, Tlv, TlvEntry}; use crate::tlv::{tag::Tag, Tlv, Value};
use crate::{apdu, keys, CardCaps, CardClientBox, KeyType}; use crate::{apdu, keys, CardCaps, CardClientBox, KeyType};
/// Low-level access to OpenPGP card functionality. /// Low-level access to OpenPGP card functionality.
@ -103,11 +103,11 @@ impl CardApp {
pub fn get_app_data(&mut self) -> Result<ApplicationRelatedData> { pub fn get_app_data(&mut self) -> Result<ApplicationRelatedData> {
let ad = commands::get_application_data(); let ad = commands::get_application_data();
let resp = apdu::send_command(&mut self.card_client, ad, true)?; let resp = apdu::send_command(&mut self.card_client, ad, true)?;
let entry = TlvEntry::from(resp.data()?, true)?; let value = Value::from(resp.data()?, true)?;
log::debug!(" App data TlvEntry: {:x?}", entry); log::debug!(" App data Value: {:x?}", value);
Ok(ApplicationRelatedData(Tlv(Tag::from([0x6E]), entry))) Ok(ApplicationRelatedData(Tlv::new(Tag::from([0x6E]), value)))
} }
/// Get data from "private use" DO. /// Get data from "private use" DO.
@ -180,11 +180,11 @@ impl CardApp {
resp.check_ok()?; resp.check_ok()?;
let tlv = Tlv::try_from(resp.data()?)?; let tlv = Tlv::try_from(resp.data()?)?;
let res = tlv.find(&Tag::from([0x93])).ok_or_else(|| { let res = tlv.find(&[0x93].into()).ok_or_else(|| {
anyhow!("Couldn't get SecuritySupportTemplate DO") anyhow!("Couldn't get SecuritySupportTemplate DO")
})?; })?;
if let TlvEntry::S(data) = res { if let Value::S(data) = res {
let mut data = data.to_vec(); let mut data = data.to_vec();
assert_eq!(data.len(), 3); assert_eq!(data.len(), 3);
@ -227,9 +227,9 @@ impl CardApp {
num: u8, num: u8,
tag: &[u8], tag: &[u8],
) -> Result<Response, OpenpgpCardError> { ) -> Result<Response, OpenpgpCardError> {
let tlv = Tlv( let tlv = Tlv::new(
Tag(vec![0x60]), [0x60],
TlvEntry::C(vec![Tlv(Tag(vec![0x5c]), TlvEntry::S(tag.to_vec()))]), Value::C(vec![Tlv::new([0x5c], Value::S(tag.to_vec()))]),
); );
let data = tlv.serialize(); let data = tlv.serialize();
@ -342,13 +342,13 @@ impl CardApp {
} }
Cryptogram::ECDH(eph) => { Cryptogram::ECDH(eph) => {
// External Public Key // External Public Key
let epk = Tlv(Tag(vec![0x86]), TlvEntry::S(eph.to_vec())); let epk = Tlv::new([0x86], Value::S(eph.to_vec()));
// Public Key DO // Public Key DO
let pkdo = Tlv(Tag(vec![0x7f, 0x49]), TlvEntry::C(vec![epk])); let pkdo = Tlv::new([0x7f, 0x49], Value::C(vec![epk]));
// Cipher DO // Cipher DO
let cdo = Tlv(Tag(vec![0xa6]), TlvEntry::C(vec![pkdo])); let cdo = Tlv::new([0xa6], Value::C(vec![pkdo]));
self.pso_decipher(cdo.serialize()) self.pso_decipher(cdo.serialize())
} }
@ -378,24 +378,21 @@ impl CardApp {
) -> Result<Vec<u8>, OpenpgpCardError> { ) -> Result<Vec<u8>, OpenpgpCardError> {
let data = match hash { let data = match hash {
Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => { Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => {
let tlv = Tlv( let tlv = Tlv::new(
Tag(vec![0x30]), [0x30],
TlvEntry::C(vec![ Value::C(vec![
Tlv( Tlv::new(
Tag(vec![0x30]), [0x30],
TlvEntry::C(vec![ Value::C(vec![
Tlv( Tlv::new(
Tag(vec![0x06]), [0x06],
// unwrapping is ok, for SHA* // unwrapping is ok, for SHA*
TlvEntry::S(hash.oid().unwrap().to_vec()), Value::S(hash.oid().unwrap().to_vec()),
), ),
Tlv(Tag(vec![0x05]), TlvEntry::S(vec![])), Tlv::new([0x05], Value::S(vec![])),
]), ]),
), ),
Tlv( Tlv::new([0x04], Value::S(hash.digest().to_vec())),
Tag(vec![0x04]),
TlvEntry::S(hash.digest().to_vec()),
),
]), ]),
); );

View file

@ -6,8 +6,7 @@ use std::convert::TryFrom;
use anyhow::Result; use anyhow::Result;
use crate::card_do::{Cardholder, Sex}; use crate::card_do::{Cardholder, Sex};
use crate::tlv::tag::Tag; use crate::tlv::{Tlv, Value};
use crate::tlv::{Tlv, TlvEntry};
impl Cardholder { impl Cardholder {
pub fn name(&self) -> Option<&str> { pub fn name(&self) -> Option<&str> {
@ -27,15 +26,15 @@ impl TryFrom<&[u8]> for Cardholder {
type Error = anyhow::Error; type Error = anyhow::Error;
fn try_from(data: &[u8]) -> Result<Self> { fn try_from(data: &[u8]) -> Result<Self> {
let entry = TlvEntry::from(data, true)?; let value = Value::from(data, true)?;
let tlv = Tlv(Tag(vec![0x65]), entry); let tlv = Tlv::new([0x65], value);
let name: Option<String> = tlv let name: Option<String> = tlv
.find(&Tag::from(&[0x5b][..])) .find(&[0x5b].into())
.map(|v| String::from_utf8_lossy(&v.serialize()).to_string()); .map(|v| String::from_utf8_lossy(&v.serialize()).to_string());
let lang: Option<Vec<[char; 2]>> = let lang: Option<Vec<[char; 2]>> =
tlv.find(&Tag::from(&[0x5f, 0x2d][..])).map(|v| { tlv.find(&[0x5f, 0x2d].into()).map(|v| {
v.serialize() v.serialize()
.chunks(2) .chunks(2)
.map(|c| [c[0] as char, c[1] as char]) .map(|c| [c[0] as char, c[1] as char])
@ -43,7 +42,7 @@ impl TryFrom<&[u8]> for Cardholder {
}); });
let sex = tlv let sex = tlv
.find(&Tag::from(&[0x5f, 0x35][..])) .find(&[0x5f, 0x35].into())
.map(|v| v.serialize()) .map(|v| v.serialize())
.filter(|v| v.len() == 1) .filter(|v| v.len() == 1)
.map(|v| Sex::from(v[0])); .map(|v| Sex::from(v[0]));

View file

@ -10,7 +10,7 @@ use std::convert::TryInto;
use crate::algorithm::Algo; use crate::algorithm::Algo;
use crate::errors::OpenpgpCardError; use crate::errors::OpenpgpCardError;
use crate::tlv::{tag::Tag, Tlv}; use crate::tlv::Tlv;
use crate::KeyType; use crate::KeyType;
mod algo_attrs; mod algo_attrs;
@ -38,7 +38,7 @@ impl ApplicationRelatedData {
/// Application identifier (AID), ISO 7816-4 /// Application identifier (AID), ISO 7816-4
pub fn get_aid(&self) -> Result<ApplicationId, OpenpgpCardError> { pub fn get_aid(&self) -> Result<ApplicationId, OpenpgpCardError> {
// get from cached "application related data" // get from cached "application related data"
let aid = self.0.find(&Tag::from([0x4F])); let aid = self.0.find(&[0x4f].into());
if let Some(aid) = aid { if let Some(aid) = aid {
Ok(ApplicationId::try_from(&aid.serialize()[..])?) Ok(ApplicationId::try_from(&aid.serialize()[..])?)
@ -50,7 +50,7 @@ impl ApplicationRelatedData {
/// Historical bytes /// Historical bytes
pub fn get_historical(&self) -> Result<Historical, OpenpgpCardError> { pub fn get_historical(&self) -> Result<Historical, OpenpgpCardError> {
// get from cached "application related data" // get from cached "application related data"
let hist = self.0.find(&Tag::from([0x5F, 0x52])); let hist = self.0.find(&[0x5f, 0x52].into());
if let Some(hist) = hist { if let Some(hist) = hist {
log::debug!("Historical bytes: {:x?}", hist); log::debug!("Historical bytes: {:x?}", hist);
@ -66,7 +66,7 @@ impl ApplicationRelatedData {
&self, &self,
) -> Result<Option<ExtendedLengthInfo>> { ) -> Result<Option<ExtendedLengthInfo>> {
// get from cached "application related data" // get from cached "application related data"
let eli = self.0.find(&Tag::from([0x7F, 0x66])); let eli = self.0.find(&[0x7f, 0x66].into());
log::debug!("Extended length information: {:x?}", eli); log::debug!("Extended length information: {:x?}", eli);
@ -92,7 +92,7 @@ impl ApplicationRelatedData {
&self, &self,
) -> Result<ExtendedCap, OpenpgpCardError> { ) -> Result<ExtendedCap, OpenpgpCardError> {
// get from cached "application related data" // get from cached "application related data"
let ecap = self.0.find(&Tag::from([0xc0])); let ecap = self.0.find(&[0xc0].into());
if let Some(ecap) = ecap { if let Some(ecap) = ecap {
Ok(ExtendedCap::try_from(&ecap.serialize()[..])?) Ok(ExtendedCap::try_from(&ecap.serialize()[..])?)
@ -104,7 +104,7 @@ impl ApplicationRelatedData {
/// Algorithm attributes (for each key type) /// Algorithm attributes (for each key type)
pub fn get_algorithm_attributes(&self, key_type: KeyType) -> Result<Algo> { pub fn get_algorithm_attributes(&self, key_type: KeyType) -> Result<Algo> {
// get from cached "application related data" // get from cached "application related data"
let aa = self.0.find(&Tag::from([key_type.get_algorithm_tag()])); let aa = self.0.find(&[key_type.get_algorithm_tag()].into());
if let Some(aa) = aa { if let Some(aa) = aa {
Algo::try_from(&aa.serialize()[..]) Algo::try_from(&aa.serialize()[..])
@ -119,7 +119,7 @@ impl ApplicationRelatedData {
/// PW status Bytes /// PW status Bytes
pub fn get_pw_status_bytes(&self) -> Result<PWStatus> { pub fn get_pw_status_bytes(&self) -> Result<PWStatus> {
// get from cached "application related data" // get from cached "application related data"
let psb = self.0.find(&Tag::from([0xc4])); 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 = PWStatus::try_from(&psb.serialize())?;
@ -138,7 +138,7 @@ impl ApplicationRelatedData {
&self, &self,
) -> Result<KeySet<Fingerprint>, OpenpgpCardError> { ) -> Result<KeySet<Fingerprint>, OpenpgpCardError> {
// Get from cached "application related data" // Get from cached "application related data"
let fp = self.0.find(&Tag::from([0xc5])); 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 = fingerprint::to_keyset(&fp.serialize())?;
@ -155,7 +155,7 @@ impl ApplicationRelatedData {
pub fn get_key_generation_times( pub fn get_key_generation_times(
&self, &self,
) -> Result<KeySet<KeyGenerationTime>, OpenpgpCardError> { ) -> Result<KeySet<KeyGenerationTime>, OpenpgpCardError> {
let kg = self.0.find(&Tag::from([0xCD])); 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 = key_generation_times::from(&kg.serialize())?;

View file

@ -17,7 +17,7 @@ use crate::crypto_data::{
RSAKey, RSAPub, RSAKey, RSAPub,
}; };
use crate::errors::OpenpgpCardError; use crate::errors::OpenpgpCardError;
use crate::tlv::{tag::Tag, Tlv, TlvEntry}; use crate::tlv::{Tlv, Value};
use crate::{apdu, tlv, KeyType}; use crate::{apdu, tlv, KeyType};
/// `gen_key_with_metadata` calculates the fingerprint for a public key /// `gen_key_with_metadata` calculates the fingerprint for a public key
@ -70,10 +70,10 @@ pub(crate) fn gen_key_with_metadata(
} }
fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result<PublicKeyMaterial> { fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result<PublicKeyMaterial> {
let n = tlv.find(&Tag::new(vec![0x81])); let n = tlv.find(&[0x81].into());
let v = tlv.find(&Tag::new(vec![0x82])); let v = tlv.find(&[0x82].into());
let ec = tlv.find(&Tag::new(vec![0x86])); let ec = tlv.find(&[0x86].into());
match (n, v, ec) { match (n, v, ec) {
(Some(n), Some(v), None) => { (Some(n), Some(v), None) => {
@ -303,13 +303,13 @@ fn ecc_key_cmd(
let crt = get_crt(key_type)?; let crt = get_crt(key_type)?;
// 2) "Cardholder private key template" (7F48) // 2) "Cardholder private key template" (7F48)
let cpkt = Tlv(Tag(vec![0x7F, 0x48]), TlvEntry::S(vec![0x92, scalar_len])); let cpkt = Tlv::new([0x7F, 0x48], Value::S(vec![0x92, scalar_len]));
// 3) "Cardholder private key" (5F48) // 3) "Cardholder private key" (5F48)
let cpk = Tlv(Tag(vec![0x5F, 0x48]), TlvEntry::S(scalar_data.to_vec())); let cpk = Tlv::new([0x5F, 0x48], Value::S(scalar_data.to_vec()));
// "Extended header list (DO 4D)" (contains the three inner TLV) // "Extended header list (DO 4D)" (contains the three inner TLV)
let ehl = Tlv(Tag(vec![0x4d]), TlvEntry::C(vec![crt, cpkt, cpk])); let ehl = Tlv::new([0x4d], Value::C(vec![crt, cpkt, cpk]));
// key import command // key import command
Ok(commands::key_import(ehl.serialize().to_vec())) Ok(commands::key_import(ehl.serialize().to_vec()))
@ -327,7 +327,7 @@ fn get_crt(key_type: KeyType) -> Result<Tlv, OpenpgpCardError> {
))) )))
} }
}; };
Ok(Tlv(Tag(vec![tag]), TlvEntry::S(vec![]))) Ok(Tlv::new([tag], Value::S(vec![])))
} }
fn rsa_key_cmd( fn rsa_key_cmd(
@ -366,7 +366,7 @@ fn rsa_key_cmd(
// len q in bytes, TLV-encoded // len q in bytes, TLV-encoded
value.extend_from_slice(&tlv::tlv_encode_length(len_q_bytes)); value.extend_from_slice(&tlv::tlv_encode_length(len_q_bytes));
let cpkt = Tlv(Tag(vec![0x7F, 0x48]), TlvEntry::S(value)); let cpkt = Tlv::new([0x7F, 0x48], Value::S(value));
// 3) "Cardholder private key" (5F48) // 3) "Cardholder private key" (5F48)
// //
@ -387,10 +387,10 @@ fn rsa_key_cmd(
keydata.extend(rsa_key.get_p().iter()); keydata.extend(rsa_key.get_p().iter());
keydata.extend(rsa_key.get_q().iter()); keydata.extend(rsa_key.get_q().iter());
let cpk = Tlv(Tag(vec![0x5F, 0x48]), TlvEntry::S(keydata)); let cpk = Tlv::new([0x5F, 0x48], Value::S(keydata));
// "Extended header list (DO 4D)" // "Extended header list (DO 4D)"
let ehl = Tlv(Tag(vec![0x4d]), TlvEntry::C(vec![crt, cpkt, cpk])); let ehl = Tlv::new([0x4d], Value::C(vec![crt, cpkt, cpk]));
// key import command // key import command
Ok(commands::key_import(ehl.serialize().to_vec())) Ok(commands::key_import(ehl.serialize().to_vec()))

View file

@ -1,29 +1,38 @@
// SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name> // SPDX-FileCopyrightText: 2021 Heiko Schaefer <heiko@schaefer.name>
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use anyhow::Result;
use nom::{bytes::complete as bytes, combinator};
// mod value;
pub mod length; pub mod length;
pub mod tag; pub mod tag;
use crate::card_do::complete; use anyhow::Result;
use tag::Tag; use nom::{bytes::complete as bytes, combinator};
use std::convert::TryFrom;
use crate::card_do::complete;
use crate::tlv::tag::Tag;
/// TLV (Tag-Length-Value)
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct Tlv(pub Tag, pub TlvEntry); pub struct Tlv {
tag: Tag,
value: Value,
}
impl Tlv { impl Tlv {
pub fn find(&self, tag: &Tag) -> Option<&TlvEntry> { pub fn new<T: Into<Tag>>(tag: T, value: Value) -> Self {
if &self.0 == tag { let tag = tag.into();
Some(&self.1) Self { tag, value }
}
/// Find the first occurrence of `tag` and return its value (if any)
pub fn find(&self, tag: &Tag) -> Option<&Value> {
if &self.tag == tag {
Some(&self.value)
} else { } else {
if let TlvEntry::C(inner) = &self.1 { if let Value::C(inner) = &self.value {
for tlv in inner { for tlv in inner {
let found = tlv.find(tag); if let Some(found) = tlv.find(tag) {
if found.is_some() { return Some(found);
return found;
} }
} }
} }
@ -32,11 +41,11 @@ impl Tlv {
} }
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let value = self.1.serialize(); let value = self.value.serialize();
let length = crate::tlv::tlv_encode_length(value.len() as u16); let length = crate::tlv::tlv_encode_length(value.len() as u16);
let mut ser = Vec::new(); let mut ser = Vec::new();
ser.extend(self.0 .0.iter()); ser.extend(self.tag.get().iter());
ser.extend(length.iter()); ser.extend(length.iter());
ser.extend(value.iter()); ser.extend(value.iter());
ser ser
@ -49,12 +58,16 @@ impl Tlv {
let (input, value) = let (input, value) =
combinator::flat_map(length::length, bytes::take)(input)?; combinator::flat_map(length::length, bytes::take)(input)?;
let (_, entry) = TlvEntry::parse(value, tag.is_constructed())?; let (_, v) = Value::parse(value, tag.is_constructed())?;
Ok((input, Self(tag, entry))) Ok((input, Self::new(tag, v)))
} }
}
pub fn try_from(input: &[u8]) -> Result<Self> { impl TryFrom<&[u8]> for Tlv {
type Error = anyhow::Error;
fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
complete(Tlv::parse(input)) complete(Tlv::parse(input))
} }
} }
@ -69,16 +82,20 @@ pub fn tlv_encode_length(len: u16) -> Vec<u8> {
} }
} }
/// A TLV "value"
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum TlvEntry { pub enum Value {
/// A "constructed" value, consisting of a list of Tlv
C(Vec<Tlv>), C(Vec<Tlv>),
/// A "simple" value, consisting of binary data
S(Vec<u8>), S(Vec<u8>),
} }
impl TlvEntry { impl Value {
pub fn parse(data: &[u8], constructed: bool) -> nom::IResult<&[u8], Self> { fn parse(data: &[u8], constructed: bool) -> nom::IResult<&[u8], Self> {
match constructed { match constructed {
false => Ok((&[], TlvEntry::S(data.to_vec()))), false => Ok((&[], Value::S(data.to_vec()))),
true => { true => {
let mut c = vec![]; let mut c = vec![];
let mut input = data; let mut input = data;
@ -89,7 +106,7 @@ impl TlvEntry {
c.push(tlv); c.push(tlv);
} }
Ok((&[], TlvEntry::C(c))) Ok((&[], Value::C(c)))
} }
} }
} }
@ -100,8 +117,8 @@ impl TlvEntry {
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
match self { match self {
TlvEntry::S(data) => data.clone(), Value::S(data) => data.clone(),
TlvEntry::C(data) => { Value::C(data) => {
let mut s = vec![]; let mut s = vec![];
for t in data { for t in data {
s.extend(&t.serialize()); s.extend(&t.serialize());
@ -114,16 +131,17 @@ impl TlvEntry {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::{Tag, Tlv};
use crate::tlv::TlvEntry;
use anyhow::Result; use anyhow::Result;
use hex_literal::hex; use hex_literal::hex;
use std::convert::TryFrom;
use super::{Tlv, Value};
#[test] #[test]
fn test_tlv0() { fn test_tlv0() {
let cpkt = Tlv( let cpkt = Tlv::new(
Tag(vec![0x7F, 0x48]), [0x7F, 0x48],
TlvEntry::S(vec![ Value::S(vec![
0x91, 0x03, 0x92, 0x82, 0x01, 0x00, 0x93, 0x82, 0x01, 0x00, 0x91, 0x03, 0x92, 0x82, 0x01, 0x00, 0x93, 0x82, 0x01, 0x00,
]), ]),
); );
@ -146,9 +164,9 @@ mod test {
assert_eq!( assert_eq!(
tlv, tlv,
Tlv( Tlv::new(
Tag::from([0x5b]), [0x5b],
TlvEntry::S(hex!("546573743C3C5465737469").to_vec()) Value::S(hex!("546573743C3C5465737469").to_vec())
) )
); );
@ -156,15 +174,12 @@ mod test {
assert_eq!( assert_eq!(
tlv, tlv,
Tlv(Tag::from([0x5f, 0x2d]), TlvEntry::S(hex!("6465").to_vec())) Tlv::new([0x5f, 0x2d], Value::S(hex!("6465").to_vec()))
); );
let (input, tlv) = Tlv::parse(input).unwrap(); let (input, tlv) = Tlv::parse(input).unwrap();
assert_eq!( assert_eq!(tlv, Tlv::new([0x5f, 0x35], Value::S(hex!("31").to_vec())));
tlv,
Tlv(Tag::from([0x5f, 0x35]), TlvEntry::S(hex!("31").to_vec()))
);
assert!(input.is_empty()); assert!(input.is_empty());
@ -178,76 +193,76 @@ mod test {
let tlv = Tlv::try_from(&data[..])?; let tlv = Tlv::try_from(&data[..])?;
// outermost layer contains all bytes as value // outermost layer contains all bytes as value
let entry = tlv.find(&Tag::from([0x6e])).unwrap(); let value = tlv.find(&[0x6e].into()).unwrap();
assert_eq!(entry.serialize(), assert_eq!(value.serialize(),
hex!("4f10d27600012401030400061601918000005f520800730000e00590007f740381012073820110c00a7d000bfe080000ff0000c106010800001100c206010800001100c306010800001100da06010800001100c407ff7f7f7f030003c5500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd1000000000000000000000000000000000de0801000200030081027f660802020bfe02020bfed6020020d7020020d8020020d9020020")); hex!("4f10d27600012401030400061601918000005f520800730000e00590007f740381012073820110c00a7d000bfe080000ff0000c106010800001100c206010800001100c306010800001100da06010800001100c407ff7f7f7f030003c5500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd1000000000000000000000000000000000de0801000200030081027f660802020bfe02020bfed6020020d7020020d8020020d9020020"));
// get and verify data for ecap tag // get and verify data for ecap tag
let entry = tlv.find(&Tag::from([0xc0])).unwrap(); let value = tlv.find(&[0xc0].into()).unwrap();
assert_eq!(entry.serialize(), hex!("7d000bfe080000ff0000")); assert_eq!(value.serialize(), hex!("7d000bfe080000ff0000"));
let entry = tlv.find(&Tag::from([0x4f])).unwrap(); let value = tlv.find(&[0x4f].into()).unwrap();
assert_eq!( assert_eq!(
entry.serialize(), value.serialize(),
hex!("d2760001240103040006160191800000") hex!("d2760001240103040006160191800000")
); );
let entry = tlv.find(&Tag::from([0x5f, 0x52])).unwrap(); let value = tlv.find(&[0x5f, 0x52].into()).unwrap();
assert_eq!(entry.serialize(), hex!("00730000e0059000")); assert_eq!(value.serialize(), hex!("00730000e0059000"));
let entry = tlv.find(&Tag::from([0x7f, 0x74])).unwrap(); let value = tlv.find(&[0x7f, 0x74].into()).unwrap();
assert_eq!(entry.serialize(), hex!("810120")); assert_eq!(value.serialize(), hex!("810120"));
let entry = tlv.find(&Tag::from([0x73])).unwrap(); let value = tlv.find(&[0x73].into()).unwrap();
assert_eq!(entry.serialize(), hex!("c00a7d000bfe080000ff0000c106010800001100c206010800001100c306010800001100da06010800001100c407ff7f7f7f030003c5500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd1000000000000000000000000000000000de0801000200030081027f660802020bfe02020bfed6020020d7020020d8020020d9020020")); assert_eq!(value.serialize(), hex!("c00a7d000bfe080000ff0000c106010800001100c206010800001100c306010800001100da06010800001100c407ff7f7f7f030003c5500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cd1000000000000000000000000000000000de0801000200030081027f660802020bfe02020bfed6020020d7020020d8020020d9020020"));
let entry = tlv.find(&Tag::from([0xc0])).unwrap(); let value = tlv.find(&[0xc0].into()).unwrap();
assert_eq!(entry.serialize(), hex!("7d000bfe080000ff0000")); assert_eq!(value.serialize(), hex!("7d000bfe080000ff0000"));
let entry = tlv.find(&Tag::from([0xc1])).unwrap(); let value = tlv.find(&[0xc1].into()).unwrap();
assert_eq!(entry.serialize(), hex!("010800001100")); assert_eq!(value.serialize(), hex!("010800001100"));
let entry = tlv.find(&Tag::from([0xc2])).unwrap(); let value = tlv.find(&[0xc2].into()).unwrap();
assert_eq!(entry.serialize(), hex!("010800001100")); assert_eq!(value.serialize(), hex!("010800001100"));
let entry = tlv.find(&Tag::from([0xc3])).unwrap(); let value = tlv.find(&[0xc3].into()).unwrap();
assert_eq!(entry.serialize(), hex!("010800001100")); assert_eq!(value.serialize(), hex!("010800001100"));
let entry = tlv.find(&Tag::from([0xda])).unwrap(); let value = tlv.find(&[0xda].into()).unwrap();
assert_eq!(entry.serialize(), hex!("010800001100")); assert_eq!(value.serialize(), hex!("010800001100"));
let entry = tlv.find(&Tag::from([0xc4])).unwrap(); let value = tlv.find(&[0xc4].into()).unwrap();
assert_eq!(entry.serialize(), hex!("ff7f7f7f030003")); assert_eq!(value.serialize(), hex!("ff7f7f7f030003"));
let entry = tlv.find(&Tag::from([0xc5])).unwrap(); let value = tlv.find(&[0xc5].into()).unwrap();
assert_eq!(entry.serialize(), hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")); assert_eq!(value.serialize(), hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
let entry = tlv.find(&Tag::from([0xc6])).unwrap(); let value = tlv.find(&[0xc6].into()).unwrap();
assert_eq!(entry.serialize(), hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")); assert_eq!(value.serialize(), hex!("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
let entry = tlv.find(&Tag::from([0xcd])).unwrap(); let value = tlv.find(&[0xcd].into()).unwrap();
assert_eq!( assert_eq!(
entry.serialize(), value.serialize(),
hex!("00000000000000000000000000000000") hex!("00000000000000000000000000000000")
); );
let entry = tlv.find(&Tag::from([0xde])).unwrap(); let value = tlv.find(&[0xde].into()).unwrap();
assert_eq!(entry.serialize(), hex!("0100020003008102")); assert_eq!(value.serialize(), hex!("0100020003008102"));
let entry = tlv.find(&Tag::from([0x7f, 0x66])).unwrap(); let value = tlv.find(&[0x7f, 0x66].into()).unwrap();
assert_eq!(entry.serialize(), hex!("02020bfe02020bfe")); assert_eq!(value.serialize(), hex!("02020bfe02020bfe"));
let entry = tlv.find(&Tag::from([0xd6])).unwrap(); let value = tlv.find(&[0xd6].into()).unwrap();
assert_eq!(entry.serialize(), hex!("0020")); assert_eq!(value.serialize(), hex!("0020"));
let entry = tlv.find(&Tag::from([0xd7])).unwrap(); let value = tlv.find(&[0xd7].into()).unwrap();
assert_eq!(entry.serialize(), hex!("0020")); assert_eq!(value.serialize(), hex!("0020"));
let entry = tlv.find(&Tag::from([0xd8])).unwrap(); let value = tlv.find(&[0xd8].into()).unwrap();
assert_eq!(entry.serialize(), hex!("0020")); assert_eq!(value.serialize(), hex!("0020"));
let entry = tlv.find(&Tag::from([0xd9])).unwrap(); let value = tlv.find(&[0xd9].into()).unwrap();
assert_eq!(entry.serialize(), hex!("0020")); assert_eq!(value.serialize(), hex!("0020"));
Ok(()) Ok(())
} }
@ -258,15 +273,11 @@ mod test {
// but has been abridged and changed. It does not represent a // but has been abridged and changed. It does not represent a
// complete valid OpenPGP card DO! // complete valid OpenPGP card DO!
let a = let a = Tlv::new([0x7F, 0x48], Value::S(vec![0x92, 0x03]));
Tlv(Tag::from(&[0x7F, 0x48][..]), TlvEntry::S(vec![0x92, 0x03]));
let b = Tlv( let b = Tlv::new([0x5F, 0x48], Value::S(vec![0x1, 0x2, 0x3]));
Tag::from(&[0x5F, 0x48][..]),
TlvEntry::S(vec![0x1, 0x2, 0x3]),
);
let tlv = Tlv(Tag::from(&[0x4d][..]), TlvEntry::C(vec![a, b])); let tlv = Tlv::new([0x4d], Value::C(vec![a, b]));
assert_eq!( assert_eq!(
tlv.serialize(), tlv.serialize(),

View file

@ -7,13 +7,9 @@ use nom::{
}; };
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub struct Tag(pub Vec<u8>); pub struct Tag(Vec<u8>);
impl Tag { impl Tag {
pub fn new(t: Vec<u8>) -> Self {
Self(t)
}
pub fn is_constructed(&self) -> bool { pub fn is_constructed(&self) -> bool {
if self.0.is_empty() { if self.0.is_empty() {
false false
@ -21,6 +17,10 @@ impl Tag {
self.0[0] & 0x20 != 0 self.0[0] & 0x20 != 0
} }
} }
pub fn get(&self) -> &[u8] {
&self.0
}
} }
impl From<&[u8]> for Tag { impl From<&[u8]> for Tag {