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,
};
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};
/// Low-level access to OpenPGP card functionality.
@ -103,11 +103,11 @@ impl CardApp {
pub fn get_app_data(&mut self) -> Result<ApplicationRelatedData> {
let ad = commands::get_application_data();
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.
@ -180,11 +180,11 @@ impl CardApp {
resp.check_ok()?;
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")
})?;
if let TlvEntry::S(data) = res {
if let Value::S(data) = res {
let mut data = data.to_vec();
assert_eq!(data.len(), 3);
@ -227,9 +227,9 @@ impl CardApp {
num: u8,
tag: &[u8],
) -> Result<Response, OpenpgpCardError> {
let tlv = Tlv(
Tag(vec![0x60]),
TlvEntry::C(vec![Tlv(Tag(vec![0x5c]), TlvEntry::S(tag.to_vec()))]),
let tlv = Tlv::new(
[0x60],
Value::C(vec![Tlv::new([0x5c], Value::S(tag.to_vec()))]),
);
let data = tlv.serialize();
@ -342,13 +342,13 @@ impl CardApp {
}
Cryptogram::ECDH(eph) => {
// 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
let pkdo = Tlv(Tag(vec![0x7f, 0x49]), TlvEntry::C(vec![epk]));
let pkdo = Tlv::new([0x7f, 0x49], Value::C(vec![epk]));
// 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())
}
@ -378,24 +378,21 @@ impl CardApp {
) -> Result<Vec<u8>, OpenpgpCardError> {
let data = match hash {
Hash::SHA256(_) | Hash::SHA384(_) | Hash::SHA512(_) => {
let tlv = Tlv(
Tag(vec![0x30]),
TlvEntry::C(vec![
Tlv(
Tag(vec![0x30]),
TlvEntry::C(vec![
Tlv(
Tag(vec![0x06]),
let tlv = Tlv::new(
[0x30],
Value::C(vec![
Tlv::new(
[0x30],
Value::C(vec![
Tlv::new(
[0x06],
// 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(
Tag(vec![0x04]),
TlvEntry::S(hash.digest().to_vec()),
),
Tlv::new([0x04], Value::S(hash.digest().to_vec())),
]),
);

View file

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

View file

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

View file

@ -17,7 +17,7 @@ use crate::crypto_data::{
RSAKey, RSAPub,
};
use crate::errors::OpenpgpCardError;
use crate::tlv::{tag::Tag, Tlv, TlvEntry};
use crate::tlv::{Tlv, Value};
use crate::{apdu, tlv, KeyType};
/// `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> {
let n = tlv.find(&Tag::new(vec![0x81]));
let v = tlv.find(&Tag::new(vec![0x82]));
let n = tlv.find(&[0x81].into());
let v = tlv.find(&[0x82].into());
let ec = tlv.find(&Tag::new(vec![0x86]));
let ec = tlv.find(&[0x86].into());
match (n, v, ec) {
(Some(n), Some(v), None) => {
@ -303,13 +303,13 @@ fn ecc_key_cmd(
let crt = get_crt(key_type)?;
// 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)
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)
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
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(
@ -366,7 +366,7 @@ fn rsa_key_cmd(
// len q in bytes, TLV-encoded
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)
//
@ -387,10 +387,10 @@ fn rsa_key_cmd(
keydata.extend(rsa_key.get_p().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)"
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
Ok(commands::key_import(ehl.serialize().to_vec()))

View file

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

View file

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