use crate::Error;
pub(crate) fn der_length(len: usize) -> Vec<u8> {
if len < 128 {
vec![len as u8]
} else if len < 256 {
vec![0x81, len as u8]
} else {
vec![0x82, (len >> 8) as u8, (len & 0xff) as u8]
}
}
pub(crate) fn der_tlv(tag: u8, data: &[u8]) -> Vec<u8> {
let mut out = vec![tag];
out.extend_from_slice(&der_length(data.len()));
out.extend_from_slice(data);
out
}
pub(crate) fn parse_der_length(data: &[u8]) -> Result<(usize, usize), Error> {
if data.is_empty() {
return Err(Error::invalid_data("DER: truncated length"));
}
let first = data[0];
if first < 128 {
Ok((first as usize, 1))
} else if first == 0x81 {
if data.len() < 2 {
return Err(Error::invalid_data("DER: truncated length (0x81)"));
}
Ok((data[1] as usize, 2))
} else if first == 0x82 {
if data.len() < 3 {
return Err(Error::invalid_data("DER: truncated length (0x82)"));
}
let len = ((data[1] as usize) << 8) | (data[2] as usize);
Ok((len, 3))
} else if first == 0x83 {
if data.len() < 4 {
return Err(Error::invalid_data("DER: truncated length (0x83)"));
}
let len = ((data[1] as usize) << 16) | ((data[2] as usize) << 8) | (data[3] as usize);
Ok((len, 4))
} else {
Err(Error::invalid_data(format!(
"DER: unsupported length encoding: 0x{first:02x}"
)))
}
}
pub(crate) fn parse_der_tlv(data: &[u8]) -> Result<(u8, &[u8], usize), Error> {
if data.is_empty() {
return Err(Error::invalid_data("DER: truncated TLV"));
}
let tag = data[0];
let (len, len_bytes) = parse_der_length(&data[1..])?;
let header_len = 1 + len_bytes;
let total = header_len + len;
if data.len() < total {
return Err(Error::invalid_data(format!(
"DER: TLV truncated: need {total} bytes, have {}",
data.len()
)));
}
Ok((tag, &data[header_len..total], total))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn length_single_byte() {
assert_eq!(der_length(0), vec![0x00]);
assert_eq!(der_length(1), vec![0x01]);
assert_eq!(der_length(127), vec![0x7f]);
}
#[test]
fn length_two_byte() {
assert_eq!(der_length(128), vec![0x81, 0x80]);
assert_eq!(der_length(255), vec![0x81, 0xff]);
}
#[test]
fn length_three_byte() {
assert_eq!(der_length(256), vec![0x82, 0x01, 0x00]);
assert_eq!(der_length(65535), vec![0x82, 0xff, 0xff]);
assert_eq!(der_length(1000), vec![0x82, 0x03, 0xe8]);
}
#[test]
fn tlv_simple() {
let result = der_tlv(0x04, &[0x01, 0x02]);
assert_eq!(result, vec![0x04, 0x02, 0x01, 0x02]);
}
#[test]
fn tlv_empty() {
let result = der_tlv(0x30, &[]);
assert_eq!(result, vec![0x30, 0x00]);
}
#[test]
fn tlv_long_content() {
let data = vec![0xaa; 200];
let result = der_tlv(0x04, &data);
assert_eq!(result[0], 0x04);
assert_eq!(result[1], 0x81);
assert_eq!(result[2], 200);
assert_eq!(result.len(), 3 + 200);
}
#[test]
fn parse_length_single_byte() {
let (len, consumed) = parse_der_length(&[0x05]).unwrap();
assert_eq!(len, 5);
assert_eq!(consumed, 1);
}
#[test]
fn parse_length_two_byte() {
let (len, consumed) = parse_der_length(&[0x81, 0x80]).unwrap();
assert_eq!(len, 128);
assert_eq!(consumed, 2);
}
#[test]
fn parse_length_three_byte() {
let (len, consumed) = parse_der_length(&[0x82, 0x01, 0x00]).unwrap();
assert_eq!(len, 256);
assert_eq!(consumed, 3);
}
#[test]
fn parse_length_four_byte() {
let (len, consumed) = parse_der_length(&[0x83, 0x01, 0x00, 0x00]).unwrap();
assert_eq!(len, 65536);
assert_eq!(consumed, 4);
}
#[test]
fn parse_length_truncated() {
assert!(parse_der_length(&[]).is_err());
assert!(parse_der_length(&[0x81]).is_err());
assert!(parse_der_length(&[0x82, 0x01]).is_err());
assert!(parse_der_length(&[0x83, 0x01, 0x00]).is_err());
}
#[test]
fn parse_tlv_roundtrip() {
let original = der_tlv(0x04, &[0xde, 0xad, 0xbe, 0xef]);
let (tag, value, total) = parse_der_tlv(&original).unwrap();
assert_eq!(tag, 0x04);
assert_eq!(value, &[0xde, 0xad, 0xbe, 0xef]);
assert_eq!(total, original.len());
}
#[test]
fn parse_tlv_truncated() {
assert!(parse_der_tlv(&[]).is_err());
assert!(parse_der_tlv(&[0x04, 0x0a, 0x01, 0x02]).is_err());
}
}