#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::marker::PhantomData;
use crate::{error::DerTypeId, Error};
#[derive(Debug)]
pub struct DerIterator<'a, T> {
reader: untrusted::Reader<'a>,
marker: PhantomData<T>,
}
impl<'a, T> DerIterator<'a, T> {
pub(crate) fn new(input: untrusted::Input<'a>) -> Self {
Self {
reader: untrusted::Reader::new(input),
marker: PhantomData,
}
}
}
impl<'a, T: FromDer<'a>> Iterator for DerIterator<'a, T> {
type Item = Result<T, Error>;
fn next(&mut self) -> Option<Self::Item> {
(!self.reader.at_end()).then(|| T::from_der(&mut self.reader))
}
}
pub(crate) trait FromDer<'a>: Sized + 'a {
fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error>;
const TYPE_ID: DerTypeId;
}
pub(crate) fn read_all<'a, T: FromDer<'a>>(input: untrusted::Input<'a>) -> Result<T, Error> {
input.read_all(Error::TrailingData(T::TYPE_ID), T::from_der)
}
#[allow(clippy::upper_case_acronyms)]
#[derive(Clone, Copy, Eq, PartialEq)]
#[repr(u8)]
pub(crate) enum Tag {
Boolean = 0x01,
Integer = 0x02,
BitString = 0x03,
OctetString = 0x04,
OID = 0x06,
Enum = 0x0A,
Sequence = CONSTRUCTED | 0x10, UTCTime = 0x17,
GeneralizedTime = 0x18,
#[allow(clippy::identity_op)]
ContextSpecificConstructed0 = CONTEXT_SPECIFIC | CONSTRUCTED | 0,
ContextSpecificConstructed1 = CONTEXT_SPECIFIC | CONSTRUCTED | 1,
ContextSpecificConstructed3 = CONTEXT_SPECIFIC | CONSTRUCTED | 3,
}
pub(crate) const CONSTRUCTED: u8 = 0x20;
pub(crate) const CONTEXT_SPECIFIC: u8 = 0x80;
impl From<Tag> for usize {
#[allow(clippy::as_conversions)]
fn from(tag: Tag) -> Self {
tag as Self
}
}
impl From<Tag> for u8 {
#[allow(clippy::as_conversions)]
fn from(tag: Tag) -> Self {
tag as Self
} }
#[inline(always)]
pub(crate) fn expect_tag_and_get_value_limited<'a>(
input: &mut untrusted::Reader<'a>,
tag: Tag,
size_limit: usize,
) -> Result<untrusted::Input<'a>, Error> {
let (actual_tag, inner) = read_tag_and_get_value_limited(input, size_limit)?;
if usize::from(tag) != usize::from(actual_tag) {
return Err(Error::BadDer);
}
Ok(inner)
}
pub(crate) fn nested_limited<'a, R>(
input: &mut untrusted::Reader<'a>,
tag: Tag,
error: Error,
decoder: impl FnOnce(&mut untrusted::Reader<'a>) -> Result<R, Error>,
size_limit: usize,
) -> Result<R, Error> {
expect_tag_and_get_value_limited(input, tag, size_limit)
.map_err(|_| error)?
.read_all(error, decoder)
}
pub(crate) fn nested<'a, R>(
input: &mut untrusted::Reader<'a>,
tag: Tag,
error: Error,
decoder: impl FnOnce(&mut untrusted::Reader<'a>) -> Result<R, Error>,
) -> Result<R, Error> {
nested_limited(input, tag, error, decoder, TWO_BYTE_DER_SIZE)
}
pub(crate) fn expect_tag<'a>(
input: &mut untrusted::Reader<'a>,
tag: Tag,
) -> Result<untrusted::Input<'a>, Error> {
let (actual_tag, value) = read_tag_and_get_value_limited(input, TWO_BYTE_DER_SIZE)?;
if usize::from(tag) != usize::from(actual_tag) {
return Err(Error::BadDer);
}
Ok(value)
}
#[inline(always)]
pub(crate) fn read_tag_and_get_value<'a>(
input: &mut untrusted::Reader<'a>,
) -> Result<(u8, untrusted::Input<'a>), Error> {
read_tag_and_get_value_limited(input, TWO_BYTE_DER_SIZE)
}
#[inline(always)]
pub(crate) fn read_tag_and_get_value_limited<'a>(
input: &mut untrusted::Reader<'a>,
size_limit: usize,
) -> Result<(u8, untrusted::Input<'a>), Error> {
let tag = input.read_byte().map_err(end_of_input_err)?;
if (tag & HIGH_TAG_RANGE_START) == HIGH_TAG_RANGE_START {
return Err(Error::BadDer); }
let length = match input.read_byte().map_err(end_of_input_err)? {
n if (n & SHORT_FORM_LEN_MAX) == 0 => usize::from(n),
LONG_FORM_LEN_ONE_BYTE => {
let length_byte = input.read_byte().map_err(end_of_input_err)?;
if length_byte < SHORT_FORM_LEN_MAX {
return Err(Error::BadDer); }
usize::from(length_byte)
}
LONG_FORM_LEN_TWO_BYTES => {
let length_byte_one = usize::from(input.read_byte().map_err(end_of_input_err)?);
let length_byte_two = usize::from(input.read_byte().map_err(end_of_input_err)?);
let combined = (length_byte_one << 8) | length_byte_two;
if combined <= LONG_FORM_LEN_ONE_BYTE_MAX {
return Err(Error::BadDer); }
combined
}
LONG_FORM_LEN_THREE_BYTES => {
let length_byte_one = usize::from(input.read_byte().map_err(end_of_input_err)?);
let length_byte_two = usize::from(input.read_byte().map_err(end_of_input_err)?);
let length_byte_three = usize::from(input.read_byte().map_err(end_of_input_err)?);
let combined = (length_byte_one << 16) | (length_byte_two << 8) | length_byte_three;
if combined <= LONG_FORM_LEN_TWO_BYTES_MAX {
return Err(Error::BadDer); }
combined
}
LONG_FORM_LEN_FOUR_BYTES => {
let length_byte_one = usize::from(input.read_byte().map_err(end_of_input_err)?);
let length_byte_two = usize::from(input.read_byte().map_err(end_of_input_err)?);
let length_byte_three = usize::from(input.read_byte().map_err(end_of_input_err)?);
let length_byte_four = usize::from(input.read_byte().map_err(end_of_input_err)?);
let combined = (length_byte_one << 24)
| (length_byte_two << 16)
| (length_byte_three << 8)
| length_byte_four;
if combined <= LONG_FORM_LEN_THREE_BYTES_MAX {
return Err(Error::BadDer); }
combined
}
_ => {
return Err(Error::BadDer); }
};
if length >= size_limit {
return Err(Error::BadDer); }
let inner = input.read_bytes(length).map_err(end_of_input_err)?;
Ok((tag, inner))
}
#[cfg(feature = "alloc")]
#[allow(clippy::as_conversions)]
pub(crate) fn asn1_wrap(tag: Tag, bytes: &[u8]) -> Vec<u8> {
let len = bytes.len();
if len < SHORT_FORM_LEN_MAX.into() {
let mut ret = Vec::with_capacity(2 + len);
ret.push(tag.into()); ret.push(len as u8); ret.extend_from_slice(bytes); ret
} else {
let size = len.to_be_bytes();
let leading_zero_bytes = size
.iter()
.position(|&byte| byte != 0)
.unwrap_or(size.len());
assert!(leading_zero_bytes < size.len());
let encoded_bytes = size.len() - leading_zero_bytes;
let mut ret = Vec::with_capacity(2 + encoded_bytes + len);
let number_of_length_bytes_byte = SHORT_FORM_LEN_MAX + encoded_bytes as u8;
ret.push(tag.into()); ret.push(number_of_length_bytes_byte); ret.extend_from_slice(&size[leading_zero_bytes..]); ret.extend_from_slice(bytes); ret
}
}
pub(crate) const TWO_BYTE_DER_SIZE: usize = LONG_FORM_LEN_TWO_BYTES_MAX;
pub(crate) const MAX_DER_SIZE: usize = LONG_FORM_LEN_FOUR_BYTES_MAX;
const HIGH_TAG_RANGE_START: u8 = 31;
const SHORT_FORM_LEN_MAX: u8 = 128;
const LONG_FORM_LEN_ONE_BYTE: u8 = 0x81;
const LONG_FORM_LEN_ONE_BYTE_MAX: usize = 0xff;
const LONG_FORM_LEN_TWO_BYTES: u8 = 0x82;
const LONG_FORM_LEN_TWO_BYTES_MAX: usize = 0xff_ff;
const LONG_FORM_LEN_THREE_BYTES: u8 = 0x83;
const LONG_FORM_LEN_THREE_BYTES_MAX: usize = 0xff_ff_ff;
const LONG_FORM_LEN_FOUR_BYTES: u8 = 0x84;
const LONG_FORM_LEN_FOUR_BYTES_MAX: usize = 0xff_ff_ff_ff;
pub(crate) fn nested_of_mut<'a>(
input: &mut untrusted::Reader<'a>,
outer_tag: Tag,
inner_tag: Tag,
error: Error,
mut decoder: impl FnMut(&mut untrusted::Reader<'a>) -> Result<(), Error>,
) -> Result<(), Error> {
nested(input, outer_tag, error, |outer| {
loop {
nested(outer, inner_tag, error, |inner| decoder(inner))?;
if outer.at_end() {
break;
}
}
Ok(())
})
}
pub(crate) fn bit_string_with_no_unused_bits<'a>(
input: &mut untrusted::Reader<'a>,
) -> Result<untrusted::Input<'a>, Error> {
nested(
input,
Tag::BitString,
Error::TrailingData(DerTypeId::BitString),
|value| {
let unused_bits_at_end = value.read_byte().map_err(|_| Error::BadDer)?;
if unused_bits_at_end != 0 {
return Err(Error::BadDer);
}
Ok(value.read_bytes_to_end())
},
)
}
pub(crate) struct BitStringFlags<'a> {
raw_bits: &'a [u8],
}
impl<'a> BitStringFlags<'a> {
pub(crate) fn bit_set(&self, bit: usize) -> bool {
let byte_index = bit / 8;
let bit_shift = 7 - (bit % 8);
if self.raw_bits.len() < (byte_index + 1) {
false
} else {
((self.raw_bits[byte_index] >> bit_shift) & 1) != 0
}
}
}
pub(crate) fn bit_string_flags(input: untrusted::Input) -> Result<BitStringFlags<'_>, Error> {
input.read_all(Error::BadDer, |bit_string| {
let padding_bits = bit_string.read_byte().map_err(|_| Error::BadDer)?;
let raw_bits = bit_string.read_bytes_to_end().as_slice_less_safe();
if padding_bits > 7 || (raw_bits.is_empty() && padding_bits != 0) {
return Err(Error::BadDer);
}
let last_byte = raw_bits[raw_bits.len() - 1];
let padding_mask = (1 << padding_bits) - 1;
match padding_bits > 0 && (last_byte & padding_mask) != 0 {
true => Err(Error::BadDer),
false => Ok(BitStringFlags { raw_bits }),
}
})
}
impl<'a> FromDer<'a> for u8 {
fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
match *nonnegative_integer(reader)?.as_slice_less_safe() {
[b] => Ok(b),
_ => Err(Error::BadDer),
}
}
const TYPE_ID: DerTypeId = DerTypeId::U8;
}
pub(crate) fn nonnegative_integer<'a>(
input: &mut untrusted::Reader<'a>,
) -> Result<untrusted::Input<'a>, Error> {
let value = expect_tag(input, Tag::Integer)?;
match value
.as_slice_less_safe()
.split_first()
.ok_or(Error::BadDer)?
{
(0, rest) => {
match rest.first() {
None => Ok(value),
Some(&second) if second & 0x80 == 0x80 => Ok(untrusted::Input::from(rest)),
_ => Err(Error::BadDer),
}
}
(first, _) if first & 0x80 == 0x00 => Ok(value),
(_, _) => Err(Error::BadDer),
}
}
pub(crate) fn end_of_input_err(_: untrusted::EndOfInput) -> Error {
Error::BadDer
}
impl<'a> FromDer<'a> for bool {
fn from_der(reader: &mut untrusted::Reader<'a>) -> Result<Self, Error> {
if !reader.peek(Tag::Boolean.into()) {
return Ok(false);
}
nested(
reader,
Tag::Boolean,
Error::TrailingData(Self::TYPE_ID),
|input| match input.read_byte() {
Ok(0xff) => Ok(true),
Ok(0x00) => Ok(false),
_ => Err(Error::BadDer),
},
)
}
const TYPE_ID: DerTypeId = DerTypeId::Bool;
}
macro_rules! oid {
( $first:expr, $second:expr, $( $tail:expr ),* ) =>
(
[(40 * $first) + $second, $( $tail ),*]
)
}
#[cfg(test)]
mod tests {
use super::DerTypeId;
use std::prelude::v1::*;
#[cfg(feature = "alloc")]
#[test]
fn test_asn1_wrap() {
let wrap_in_sequence = |bytes: &[u8]| super::asn1_wrap(super::Tag::Sequence, bytes);
assert_eq!(vec![0x30, 0x00], wrap_in_sequence(&[]));
assert_eq!(
vec![0x30, 0x04, 0x00, 0x11, 0x22, 0x33],
wrap_in_sequence(&[0x00, 0x11, 0x22, 0x33])
);
let mut val = Vec::new();
val.resize(255, 0x12);
assert_eq!(
vec![0x30, 0x81, 0xff, 0x12, 0x12, 0x12],
wrap_in_sequence(&val)[..6]
);
let mut val = Vec::new();
val.resize(4660, 0x12);
wrap_in_sequence(&val);
assert_eq!(
vec![0x30, 0x82, 0x12, 0x34, 0x12, 0x12],
wrap_in_sequence(&val)[..6]
);
let mut val = Vec::new();
val.resize(0xffff, 0x12);
let result = wrap_in_sequence(&val);
assert_eq!(vec![0x30, 0x82, 0xff, 0xff, 0x12, 0x12], result[..6]);
assert_eq!(result.len(), 0xffff + 4);
let mut val = Vec::new();
val.resize(0x100000, 0x12);
let result = wrap_in_sequence(&val);
assert_eq!(vec![0x30, 0x83, 0x10, 0x00, 0x00, 0x12, 0x12], result[..7]);
assert_eq!(result.len(), 0x100000 + 5);
let mut val = Vec::new();
val.resize(0x1000000, 0x12);
let result = wrap_in_sequence(&val);
assert_eq!(
vec![0x30, 0x84, 0x01, 0x00, 0x00, 0x00, 0x12, 0x12],
result[..8]
);
assert_eq!(result.len(), 0x1000000 + 6);
}
#[test]
fn test_optional_boolean() {
use super::{Error, FromDer};
assert!(!bool::from_der(&mut bytes_reader(&[])).unwrap());
assert!(!bool::from_der(&mut bytes_reader(&[0x05, 0x00])).unwrap());
assert_eq!(
Err(Error::BadDer),
bool::from_der(&mut bytes_reader(&[0x01, 0x01, 0x42]))
);
assert!(bool::from_der(&mut bytes_reader(&[0x01, 0x01, 0xff])).unwrap());
assert!(!bool::from_der(&mut bytes_reader(&[0x01, 0x01, 0x00])).unwrap());
}
#[test]
fn test_bit_string_with_no_unused_bits() {
use super::{bit_string_with_no_unused_bits, Error};
assert_eq!(
bit_string_with_no_unused_bits(&mut bytes_reader(&[0x01, 0x01, 0xff])).unwrap_err(),
Error::TrailingData(DerTypeId::BitString),
);
assert_eq!(
bit_string_with_no_unused_bits(&mut bytes_reader(&[0x42, 0xff, 0xff])).unwrap_err(),
Error::TrailingData(DerTypeId::BitString),
);
assert_eq!(
bit_string_with_no_unused_bits(&mut bytes_reader(&[])).unwrap_err(),
Error::TrailingData(DerTypeId::BitString),
);
assert_eq!(
bit_string_with_no_unused_bits(&mut bytes_reader(&[0x03, 0x03, 0x04, 0x12, 0x34]))
.unwrap_err(),
Error::BadDer,
);
assert_eq!(
bit_string_with_no_unused_bits(&mut bytes_reader(&[0x03, 0x03, 0x00, 0x12, 0x34]))
.unwrap()
.as_slice_less_safe(),
&[0x12, 0x34],
);
}
fn bytes_reader(bytes: &[u8]) -> untrusted::Reader {
return untrusted::Reader::new(untrusted::Input::from(bytes));
}
#[test]
fn read_tag_and_get_value_default_limit() {
use super::{read_tag_and_get_value, Error};
let inputs = &[
&[EXAMPLE_TAG, 0x83, 0xFF, 0xFF, 0xFF].as_slice(),
&[EXAMPLE_TAG, 0x84, 0xFF, 0xFF, 0xFF, 0xFF].as_slice(),
];
for input in inputs {
let mut bytes = untrusted::Reader::new(untrusted::Input::from(input));
assert!(matches!(
read_tag_and_get_value(&mut bytes),
Err(Error::BadDer)
));
}
}
#[test]
fn read_tag_and_get_value_limited_high_form() {
use super::{read_tag_and_get_value_limited, Error, LONG_FORM_LEN_TWO_BYTES_MAX};
let mut bytes = untrusted::Reader::new(untrusted::Input::from(&[0xFF]));
assert!(matches!(
read_tag_and_get_value_limited(&mut bytes, LONG_FORM_LEN_TWO_BYTES_MAX),
Err(Error::BadDer)
));
}
#[test]
fn read_tag_and_get_value_limited_non_canonical() {
use super::{read_tag_and_get_value_limited, Error, LONG_FORM_LEN_TWO_BYTES_MAX};
let inputs = &[
&[EXAMPLE_TAG, 0x81, 0x01].as_slice(),
&[EXAMPLE_TAG, 0x82, 0x00, 0x01].as_slice(),
&[EXAMPLE_TAG, 0x83, 0x00, 0x00, 0x01].as_slice(),
&[EXAMPLE_TAG, 0x84, 0x00, 0x00, 0x00, 0x01].as_slice(),
];
for input in inputs {
let mut bytes = untrusted::Reader::new(untrusted::Input::from(input));
assert!(matches!(
read_tag_and_get_value_limited(&mut bytes, LONG_FORM_LEN_TWO_BYTES_MAX),
Err(Error::BadDer)
));
}
}
#[test]
#[cfg(feature = "alloc")]
fn read_tag_and_get_value_limited_limits() {
use super::{read_tag_and_get_value_limited, Error};
let short_input = &[0xFF];
let short_input_encoded = &[
&[EXAMPLE_TAG],
der_encode_length(short_input.len()).as_slice(),
short_input,
]
.concat();
let long_input = &[1_u8; 65537];
let long_input_encoded = &[
&[EXAMPLE_TAG],
der_encode_length(long_input.len()).as_slice(),
long_input,
]
.concat();
struct Testcase<'a> {
input: &'a [u8],
limit: usize,
err: Option<Error>,
}
let testcases = &[
Testcase {
input: short_input_encoded,
limit: 1,
err: Some(Error::BadDer),
},
Testcase {
input: short_input_encoded,
limit: short_input_encoded.len() + 1,
err: None,
},
Testcase {
input: long_input_encoded,
limit: long_input.len(),
err: Some(Error::BadDer),
},
Testcase {
input: long_input_encoded,
limit: long_input.len() + 1,
err: None,
},
];
for tc in testcases {
let mut bytes = untrusted::Reader::new(untrusted::Input::from(tc.input));
let res = read_tag_and_get_value_limited(&mut bytes, tc.limit);
match tc.err {
None => assert!(res.is_ok()),
Some(e) => {
let actual = res.unwrap_err();
assert_eq!(actual, e)
}
}
}
}
#[allow(clippy::as_conversions)] const EXAMPLE_TAG: u8 = super::Tag::Sequence as u8;
#[cfg(feature = "alloc")]
#[allow(clippy::as_conversions)] fn der_encode_length(length: usize) -> Vec<u8> {
if length < 128 {
vec![length as u8]
} else {
let mut encoded: Vec<u8> = Vec::new();
let mut remaining_length = length;
while remaining_length > 0 {
let byte = (remaining_length & 0xFF) as u8;
encoded.insert(0, byte);
remaining_length >>= 8;
}
let length_octet = encoded.len() as u8 | 0x80;
encoded.insert(0, length_octet);
encoded
}
}
#[test]
fn misencoded_bit_string_flags() {
use super::{bit_string_flags, Error};
let bad_padding_example = untrusted::Input::from(&[
0x08, 0x06, ]);
assert!(matches!(
bit_string_flags(bad_padding_example),
Err(Error::BadDer)
));
let bad_padding_example = untrusted::Input::from(&[
0x01, ]);
assert!(matches!(
bit_string_flags(bad_padding_example),
Err(Error::BadDer)
));
}
#[test]
fn valid_bit_string_flags() {
use super::bit_string_flags;
let example_key_usage = untrusted::Input::from(&[
0x01, 0x06, ]);
let res = bit_string_flags(example_key_usage).unwrap();
assert!(!res.bit_set(0));
assert!(!res.bit_set(1));
assert!(!res.bit_set(2));
assert!(!res.bit_set(3));
assert!(!res.bit_set(4));
assert!(res.bit_set(5));
assert!(res.bit_set(6));
assert!(!res.bit_set(7));
assert!(!res.bit_set(8));
assert!(!res.bit_set(256));
}
#[test]
fn test_small_nonnegative_integer() {
use super::{Error, FromDer, Tag};
for value in 0..=127 {
let data = [Tag::Integer.into(), 1, value];
let mut rd = untrusted::Reader::new(untrusted::Input::from(&data));
assert_eq!(u8::from_der(&mut rd), Ok(value),);
}
for value in 128..=255 {
let data = [Tag::Integer.into(), 2, 0x00, value];
let mut rd = untrusted::Reader::new(untrusted::Input::from(&data));
assert_eq!(u8::from_der(&mut rd), Ok(value),);
}
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[
Tag::Sequence.into(),
1,
1
]))),
Err(Error::BadDer)
);
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[
Tag::Integer.into(),
1,
0xff
]))),
Err(Error::BadDer)
);
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[
Tag::Integer.into(),
2,
0x01,
0x00
]))),
Err(Error::BadDer)
);
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[
Tag::Integer.into(),
2,
0x00,
0x05
]))),
Err(Error::BadDer)
);
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[]))),
Err(Error::BadDer)
);
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[
Tag::Integer.into(),
]))),
Err(Error::BadDer)
);
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[
Tag::Integer.into(),
1,
]))),
Err(Error::BadDer)
);
assert_eq!(
u8::from_der(&mut untrusted::Reader::new(untrusted::Input::from(&[
Tag::Integer.into(),
2,
0
]))),
Err(Error::BadDer)
);
}
}