Cleanup Tlv, Tag, Value:
- Make Tlv/Tag fields private. - Rename TlvEntry to Value. - impl TryFrom<&[u8]> for Tlv
This commit is contained in:
parent
821b5f0dae
commit
c25c8b55b8
6 changed files with 153 additions and 146 deletions
|
@ -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()),
|
|
||||||
),
|
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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]));
|
||||||
|
|
|
@ -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())?;
|
||||||
|
|
|
@ -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()))
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue