use thiserror::Error;
#[derive(Debug, Error, PartialEq, Eq)]
pub enum TLVError {
#[error("Unexpected end of data while parsing tag")]
UnexpectedEndTag,
#[error("Unexpected end of data while parsing length")]
UnexpectedEndLength,
#[error("Unexpected end of data while parsing value")]
UnexpectedEndValue,
#[error("Invalid length encoding")]
InvalidLength,
#[error("Length too large: {0}")]
LengthTooLarge(usize),
#[error("Only two bytes for tags supported")]
TagTooLong,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TLV {
pub tag: u32,
pub value: Vec<u8>,
pub subs: Vec<TLV>,
}
impl TLV {
pub fn new(tag: u32, value: Vec<u8>) -> Self {
Self {
tag,
value,
subs: Vec::new(),
}
}
pub fn constructed(tag: u32, children: Vec<TLV>) -> Self {
Self {
tag,
value: Vec::new(),
subs: children,
}
}
pub fn get_t(&self) -> u16 {
self.tag as u16
}
pub fn get_l(&self) -> u16 {
self.value.len() as u16
}
pub fn get_v(&self) -> &[u8] {
&self.value
}
pub fn if_recursive(&self) -> bool {
!self.subs.is_empty()
}
pub fn is_constructed(&self) -> bool {
let first_byte = self.first_tag_byte();
(first_byte & 0x20) != 0
}
fn first_tag_byte(&self) -> u8 {
if self.tag > 0xFFFF {
((self.tag >> 16) & 0xFF) as u8
} else if self.tag > 0xFF {
((self.tag >> 8) & 0xFF) as u8
} else {
(self.tag & 0xFF) as u8
}
}
pub fn find_tag(&self, tag: u16) -> Option<TLV> {
if self.tag == tag as u32 {
return Some(self.clone());
}
for tlv in &self.subs {
if let Some(found) = tlv.find_tag(tag) {
return Some(found);
}
}
None
}
pub fn find(&self, tag: u32) -> Option<&TLV> {
if self.tag == tag {
return Some(self);
}
for child in &self.subs {
if let Some(found) = child.find(tag) {
return Some(found);
}
}
None
}
pub fn find_child(&self, tag: u32) -> Option<&TLV> {
self.subs.iter().find(|c| c.tag == tag)
}
pub fn get_aid(&self) -> Option<Vec<u8>> {
self.find_tag(0x4F).map(|t| t.value.clone())
}
pub fn get_historical_bytes(&self) -> Option<Vec<u8>> {
self.find_tag(0x5F52).map(|t| t.value.clone())
}
pub fn get_fingerprints(&self) -> Option<Vec<u8>> {
self.find_tag(0xC5).map(|t| t.value.clone())
}
pub fn get_name(&self) -> Option<Vec<u8>> {
self.find_tag(0x5B).map(|t| t.value.clone())
}
pub fn get_signature_algo_attributes(&self) -> Option<Vec<u8>> {
self.find_tag(0xC1).map(|t| t.value.clone())
}
pub fn get_encryption_algo_attributes(&self) -> Option<Vec<u8>> {
self.find_tag(0xC2).map(|t| t.value.clone())
}
pub fn get_authentication_algo_attributes(&self) -> Option<Vec<u8>> {
self.find_tag(0xC3).map(|t| t.value.clone())
}
pub fn get_pin_tries(&self) -> Option<Vec<u8>> {
self.find_tag(0xC4).map(|t| t.value.clone())
}
pub fn get_key_information(&self) -> Option<Vec<u8>> {
self.find_tag(0xDE).map(|t| t.value.clone())
}
pub fn get_number_of_signatures(&self) -> Option<Vec<u8>> {
self.find_tag(0x93).map(|t| t.value.clone())
}
}
impl TLV {
pub fn children(&self) -> &Vec<TLV> {
&self.subs
}
pub fn value(&self) -> &[u8] {
&self.value
}
}
pub fn read_list(data: &[u8], recursive: bool) -> Vec<TLV> {
let mut result = Vec::new();
let mut remaining = data.to_vec();
while !remaining.is_empty() {
if remaining[0] == 0x00 || remaining[0] == 0xFF {
remaining.remove(0);
continue;
}
match read_single(remaining.clone(), recursive) {
Ok((tlv, rest)) => {
result.push(tlv);
remaining = rest;
}
Err(_) => break,
}
}
result
}
pub fn read_single(data: Vec<u8>, recursive: bool) -> Result<(TLV, Vec<u8>), String> {
if data.is_empty() {
return Err("Empty data".to_string());
}
let mut offset = 0;
let (tag, tag_len) = parse_tag(&data[offset..])
.map_err(|e| e.to_string())?;
offset += tag_len;
if offset >= data.len() {
return Err("Unexpected end of data while parsing length".to_string());
}
let (length, len_len) = parse_length(&data[offset..])
.map_err(|e| e.to_string())?;
offset += len_len;
if offset + length > data.len() {
return Err("Unexpected end of data while parsing value".to_string());
}
let value = data[offset..offset + length].to_vec();
offset += length;
let first_byte = if tag > 0xFFFF {
((tag >> 16) & 0xFF) as u8
} else if tag > 0xFF {
((tag >> 8) & 0xFF) as u8
} else {
(tag & 0xFF) as u8
};
let subs = if recursive && (first_byte & 0x20) != 0 && !value.is_empty() {
read_list(&value, true)
} else {
Vec::new()
};
let remaining = data[offset..].to_vec();
Ok((TLV { tag, value, subs }, remaining))
}
fn parse_tag(data: &[u8]) -> Result<(u32, usize), TLVError> {
if data.is_empty() {
return Err(TLVError::UnexpectedEndTag);
}
let first = data[0];
if (first & 0x1F) != 0x1F {
return Ok((first as u32, 1));
}
if data.len() < 2 {
return Err(TLVError::UnexpectedEndTag);
}
let second = data[1];
if (second & 0x80) == 0 {
let tag = ((first as u32) << 8) | (second as u32);
return Ok((tag, 2));
}
if data.len() < 3 {
return Err(TLVError::UnexpectedEndTag);
}
let third = data[2];
let tag = ((first as u32) << 16) | ((second as u32) << 8) | (third as u32);
Ok((tag, 3))
}
fn parse_length(data: &[u8]) -> Result<(usize, usize), TLVError> {
if data.is_empty() {
return Err(TLVError::UnexpectedEndLength);
}
let first = data[0];
if (first & 0x80) == 0 {
return Ok((first as usize, 1));
}
let num_bytes = (first & 0x7F) as usize;
if num_bytes == 0 {
return Err(TLVError::InvalidLength);
}
if num_bytes > 4 {
return Err(TLVError::LengthTooLarge(num_bytes));
}
if data.len() < 1 + num_bytes {
return Err(TLVError::UnexpectedEndLength);
}
let mut length: usize = 0;
for i in 0..num_bytes {
length = (length << 8) | (data[1 + i] as usize);
}
Ok((length, 1 + num_bytes))
}
pub struct TLVParser;
impl TLVParser {
pub fn parse(data: &[u8]) -> Result<Vec<TLV>, TLVError> {
Ok(read_list(data, true))
}
pub fn parse_one(data: &[u8]) -> Result<(TLV, usize), TLVError> {
match read_single(data.to_vec(), true) {
Ok((tlv, remaining)) => {
let consumed = data.len() - remaining.len();
Ok((tlv, consumed))
}
Err(_) => Err(TLVError::InvalidLength), }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_tlv() {
let data = hex::decode("4F08D276000124010304").unwrap();
let tlvs = read_list(&data, true);
assert_eq!(tlvs.len(), 1);
assert_eq!(tlvs[0].tag, 0x4F);
assert_eq!(tlvs[0].get_t(), 0x4F);
assert_eq!(tlvs[0].value, hex::decode("D276000124010304").unwrap());
}
#[test]
fn test_two_byte_tag() {
let data = hex::decode("5F500B6578616D706C652E636F6D").unwrap();
let tlvs = read_list(&data, true);
assert_eq!(tlvs.len(), 1);
assert_eq!(tlvs[0].tag, 0x5F50);
assert_eq!(tlvs[0].value, b"example.com");
}
#[test]
fn test_constructed_tlv() {
let data = hex::decode("65085B06446F65203C3C").unwrap();
let tlvs = read_list(&data, true);
assert_eq!(tlvs.len(), 1);
assert!(tlvs[0].is_constructed());
assert!(tlvs[0].if_recursive());
assert_eq!(tlvs[0].subs.len(), 1);
assert_eq!(tlvs[0].subs[0].tag, 0x5B);
}
#[test]
fn test_find_tag() {
let data = hex::decode("6E0A4F08D276000124010304").unwrap();
let tlvs = read_list(&data, true);
let found = tlvs[0].find_tag(0x4F);
assert!(found.is_some());
assert_eq!(found.unwrap().tag, 0x4F);
}
#[test]
fn test_get_aid() {
let data = hex::decode("6E0A4F08D276000124010304").unwrap();
let tlvs = read_list(&data, true);
let aid = tlvs[0].get_aid();
assert!(aid.is_some());
assert_eq!(aid.unwrap(), hex::decode("D276000124010304").unwrap());
}
#[test]
fn test_multiple_tlvs() {
let data = hex::decode("4F0201025B03414243").unwrap();
let tlvs = read_list(&data, true);
assert_eq!(tlvs.len(), 2);
assert_eq!(tlvs[0].tag, 0x4F);
assert_eq!(tlvs[1].tag, 0x5B);
}
#[test]
fn test_long_length() {
let mut data = vec![0xC0, 0x81, 0x80];
data.extend(vec![0x00; 128]);
let tlvs = read_list(&data, true);
assert_eq!(tlvs.len(), 1);
assert_eq!(tlvs[0].value.len(), 128);
}
#[test]
fn test_filler_bytes() {
let data = hex::decode("00FF4F020102").unwrap();
let tlvs = read_list(&data, true);
assert_eq!(tlvs.len(), 1);
assert_eq!(tlvs[0].tag, 0x4F);
}
}