pub const TAG_INTEGER: u8 = 0x02;
pub const TAG_BIT_STRING: u8 = 0x03;
pub const TAG_OCTET_STRING: u8 = 0x04;
pub const TAG_NULL: u8 = 0x05;
pub const TAG_OID: u8 = 0x06;
pub const TAG_SEQUENCE: u8 = 0x30;
pub struct DerEncoder {
buf: Vec<u8>,
}
impl DerEncoder {
pub fn new() -> Self {
Self { buf: Vec::new() }
}
pub fn finish(self) -> Vec<u8> {
self.buf
}
pub fn write_length(&mut self, len: usize) {
if len < 0x80 {
self.buf.push(len as u8);
} else if len < 0x100 {
self.buf.push(0x81);
self.buf.push(len as u8);
} else if len < 0x10000 {
self.buf.push(0x82);
self.buf.push((len >> 8) as u8);
self.buf.push((len & 0xFF) as u8);
} else {
self.buf.push(0x83);
self.buf.push((len >> 16) as u8);
self.buf.push(((len >> 8) & 0xFF) as u8);
self.buf.push((len & 0xFF) as u8);
}
}
pub fn sequence(&mut self, content: &[u8]) {
self.buf.push(TAG_SEQUENCE);
self.write_length(content.len());
self.buf.extend_from_slice(content);
}
pub fn integer(&mut self, value: &[u8]) {
let mut start = 0;
while start < value.len() - 1 && value[start] == 0 {
start += 1;
}
let val = &value[start..];
let needs_pad = val[0] & 0x80 != 0;
let total = val.len() + if needs_pad { 1 } else { 0 };
self.buf.push(TAG_INTEGER);
self.write_length(total);
if needs_pad {
self.buf.push(0x00);
}
self.buf.extend_from_slice(val);
}
pub fn integer_u64(&mut self, v: u64) {
if v == 0 {
self.buf.extend_from_slice(&[TAG_INTEGER, 1, 0]);
return;
}
let be = v.to_be_bytes();
let start = be.iter().position(|&b| b != 0).unwrap_or(7);
self.integer(&be[start..]);
}
pub fn octet_string(&mut self, data: &[u8]) {
self.buf.push(TAG_OCTET_STRING);
self.write_length(data.len());
self.buf.extend_from_slice(data);
}
pub fn bit_string(&mut self, data: &[u8]) {
self.buf.push(TAG_BIT_STRING);
self.write_length(data.len() + 1);
self.buf.push(0x00); self.buf.extend_from_slice(data);
}
pub fn oid(&mut self, encoded: &[u8]) {
self.buf.push(TAG_OID);
self.write_length(encoded.len());
self.buf.extend_from_slice(encoded);
}
pub fn null(&mut self) {
self.buf.extend_from_slice(&[TAG_NULL, 0x00]);
}
pub fn context_explicit(&mut self, tag_num: u8, content: &[u8]) {
self.buf.push(0xA0 | tag_num);
self.write_length(content.len());
self.buf.extend_from_slice(content);
}
pub fn raw(&mut self, data: &[u8]) {
self.buf.extend_from_slice(data);
}
}
pub struct DerDecoder<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> DerDecoder<'a> {
pub fn new(data: &'a [u8]) -> Self {
Self { data, pos: 0 }
}
pub fn remaining(&self) -> usize {
self.data.len() - self.pos
}
pub fn is_empty(&self) -> bool {
self.pos >= self.data.len()
}
pub fn peek_tag(&self) -> Option<u8> {
self.data.get(self.pos).copied()
}
pub fn read_tlv(&mut self) -> Option<(u8, &'a [u8])> {
let tag = *self.data.get(self.pos)?;
self.pos += 1;
let len = self.read_length()?;
if self.pos + len > self.data.len() {
return None;
}
let content = &self.data[self.pos..self.pos + len];
self.pos += len;
Some((tag, content))
}
fn read_length(&mut self) -> Option<usize> {
let first = *self.data.get(self.pos)?;
self.pos += 1;
if first < 0x80 {
Some(first as usize)
} else if first == 0x81 {
let b = *self.data.get(self.pos)? as usize;
self.pos += 1;
Some(b)
} else if first == 0x82 {
let hi = *self.data.get(self.pos)? as usize;
let lo = *self.data.get(self.pos + 1)? as usize;
self.pos += 2;
Some((hi << 8) | lo)
} else if first == 0x83 {
let a = *self.data.get(self.pos)? as usize;
let b = *self.data.get(self.pos + 1)? as usize;
let c = *self.data.get(self.pos + 2)? as usize;
self.pos += 3;
Some((a << 16) | (b << 8) | c)
} else {
None
}
}
pub fn read_sequence(&mut self) -> Option<DerDecoder<'a>> {
let (tag, content) = self.read_tlv()?;
if tag != TAG_SEQUENCE {
return None;
}
Some(DerDecoder::new(content))
}
pub fn read_integer(&mut self) -> Option<&'a [u8]> {
let (tag, content) = self.read_tlv()?;
if tag != TAG_INTEGER || content.is_empty() {
return None;
}
if content[0] == 0x00 && content.len() > 1 {
Some(&content[1..])
} else {
Some(content)
}
}
pub fn read_integer_u64(&mut self) -> Option<u64> {
let bytes = self.read_integer()?;
let mut v = 0u64;
for &b in bytes {
v = (v << 8) | b as u64;
}
Some(v)
}
pub fn read_octet_string(&mut self) -> Option<&'a [u8]> {
let (tag, content) = self.read_tlv()?;
if tag != TAG_OCTET_STRING {
return None;
}
Some(content)
}
pub fn read_bit_string(&mut self) -> Option<&'a [u8]> {
let (tag, content) = self.read_tlv()?;
if tag != TAG_BIT_STRING || content.is_empty() {
return None;
}
Some(&content[1..])
}
pub fn read_oid(&mut self) -> Option<&'a [u8]> {
let (tag, content) = self.read_tlv()?;
if tag != TAG_OID {
return None;
}
Some(content)
}
pub fn read_null(&mut self) -> Option<()> {
let (tag, content) = self.read_tlv()?;
if tag != TAG_NULL || !content.is_empty() {
return None;
}
Some(())
}
pub fn read_context_explicit(&mut self, tag_num: u8) -> Option<DerDecoder<'a>> {
let expected = 0xA0 | tag_num;
if self.peek_tag() != Some(expected) {
return None;
}
let (_, content) = self.read_tlv()?;
Some(DerDecoder::new(content))
}
pub fn skip(&mut self) -> Option<()> {
self.read_tlv().map(|_| ())
}
}
pub const OID_RSA: &[u8] = &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01];
pub const OID_EC_PUBLIC_KEY: &[u8] = &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01];
pub const OID_SECP256R1: &[u8] = &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07];
pub const OID_SECP384R1: &[u8] = &[0x2B, 0x81, 0x04, 0x00, 0x22];
pub const OID_SECP521R1: &[u8] = &[0x2B, 0x81, 0x04, 0x00, 0x23];
pub const OID_SECP256K1: &[u8] = &[0x2B, 0x81, 0x04, 0x00, 0x0A];
pub const OID_BRAINPOOL_P256R1: &[u8] = &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07];
pub const OID_BRAINPOOL_P384R1: &[u8] = &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B];
pub const OID_BRAINPOOL_P512R1: &[u8] = &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D];
pub const OID_ED25519: &[u8] = &[0x2B, 0x65, 0x70];
pub const OID_X25519: &[u8] = &[0x2B, 0x65, 0x6E];
pub const OID_X448: &[u8] = &[0x2B, 0x65, 0x6F];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn roundtrip_integer() {
let val = [0x00, 0x80, 0xFF]; let mut enc = DerEncoder::new();
enc.integer(&val);
let der = enc.finish();
let mut dec = DerDecoder::new(&der);
let got = dec.read_integer().unwrap();
assert_eq!(got, &[0x80, 0xFF]);
}
#[test]
fn roundtrip_integer_u64() {
for v in [0u64, 1, 127, 128, 255, 256, 65535, 0xDEADBEEF] {
let mut enc = DerEncoder::new();
enc.integer_u64(v);
let der = enc.finish();
let mut dec = DerDecoder::new(&der);
assert_eq!(dec.read_integer_u64().unwrap(), v, "v={}", v);
}
}
#[test]
fn roundtrip_sequence() {
let mut inner = DerEncoder::new();
inner.integer_u64(42);
inner.octet_string(b"hello");
let content = inner.finish();
let mut outer = DerEncoder::new();
outer.sequence(&content);
let der = outer.finish();
let mut dec = DerDecoder::new(&der);
let mut seq = dec.read_sequence().unwrap();
assert_eq!(seq.read_integer_u64().unwrap(), 42);
assert_eq!(seq.read_octet_string().unwrap(), b"hello");
assert!(seq.is_empty());
}
#[test]
fn roundtrip_bit_string() {
let data = [0x04, 0x01, 0x02]; let mut enc = DerEncoder::new();
enc.bit_string(&data);
let der = enc.finish();
let mut dec = DerDecoder::new(&der);
let got = dec.read_bit_string().unwrap();
assert_eq!(got, &data);
}
#[test]
fn roundtrip_oid() {
let mut enc = DerEncoder::new();
enc.oid(OID_RSA);
let der = enc.finish();
let mut dec = DerDecoder::new(&der);
assert_eq!(dec.read_oid().unwrap(), OID_RSA);
}
#[test]
fn context_explicit_tag() {
let mut inner = DerEncoder::new();
inner.integer_u64(1);
let content = inner.finish();
let mut enc = DerEncoder::new();
enc.context_explicit(0, &content);
let der = enc.finish();
let mut dec = DerDecoder::new(&der);
let mut ctx = dec.read_context_explicit(0).unwrap();
assert_eq!(ctx.read_integer_u64().unwrap(), 1);
}
#[test]
fn large_length_encoding() {
let data = vec![0xABu8; 256];
let mut enc = DerEncoder::new();
enc.octet_string(&data);
let der = enc.finish();
let mut dec = DerDecoder::new(&der);
let got = dec.read_octet_string().unwrap();
assert_eq!(got, &data[..]);
}
}