use crate::ber::*;
use crate::error::*;
use der::DerObject;
use nom::{be_u8, Context, Err, ErrorKind, IResult, Needed};
pub fn parse_der(i: &[u8]) -> IResult<&[u8], DerObject, u32> {
do_parse! {
i,
hdr: der_read_element_header >>
error_if!(hdr.len > ::std::u32::MAX as u64, ErrorKind::Custom(BER_INVALID_LENGTH)) >>
content: apply!(der_read_element_content,hdr) >>
( content )
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! der_constraint_fail_if(
($slice:expr, $cond:expr) => (
{
if $cond {
return Err(::nom::Err::Error(error_position!($slice, ErrorKind::Custom(DER_CONSTRAINT_FAIL))));
}
}
);
);
pub fn parse_der_with_tag(i: &[u8], tag: BerTag) -> IResult<&[u8], BerObject> {
do_parse! {
i,
hdr: der_read_element_header >>
error_if!(hdr.tag != tag, ErrorKind::Custom(BER_TAG_ERROR)) >>
o: apply!(der_read_element_content_as, hdr.tag, hdr.len as usize, hdr.is_constructed(), 0) >>
( BerObject::from_header_and_content(hdr, o) )
}
}
#[inline]
pub fn parse_der_endofcontent(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::EndOfContent)
}
#[inline]
pub fn parse_der_bool(i: &[u8]) -> IResult<&[u8], DerObject> {
parse_der_with_tag(i, BerTag::Boolean)
}
#[inline]
pub fn parse_der_integer(i: &[u8]) -> IResult<&[u8], DerObject> {
parse_der_with_tag(i, BerTag::Integer)
}
pub fn parse_der_bitstring(i: &[u8]) -> IResult<&[u8], DerObject> {
do_parse! {
i,
hdr: der_read_element_header >>
error_if!(hdr.tag != BerTag::BitString, ErrorKind::Custom(BER_TAG_ERROR)) >>
error_if!(hdr.is_constructed(), ErrorKind::Custom(DER_CONSTRAINT_FAIL)) >>
b: apply!(der_read_content_bitstring, hdr.len as usize) >>
( DerObject::from_header_and_content(hdr, b) )
}
}
#[inline]
pub fn parse_der_octetstring(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::OctetString)
}
#[inline]
pub fn parse_der_null(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::Null)
}
#[inline]
pub fn parse_der_oid(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::Oid)
}
#[inline]
pub fn parse_der_enum(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::Enumerated)
}
#[inline]
pub fn parse_der_utf8string(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::Utf8String)
}
#[inline]
pub fn parse_der_relative_oid(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::RelativeOid)
}
#[inline]
pub fn parse_der_sequence(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::Sequence)
}
#[inline]
pub fn parse_der_set(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::Set)
}
#[inline]
pub fn parse_der_numericstring(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::NumericString)
}
#[inline]
pub fn parse_der_printablestring(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::PrintableString)
}
#[inline]
pub fn parse_der_t61string(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::T61String)
}
#[inline]
pub fn parse_der_ia5string(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::Ia5String)
}
#[inline]
pub fn parse_der_utctime(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::UtcTime)
}
#[inline]
pub fn parse_der_generalizedtime(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::GeneralizedTime)
}
#[inline]
pub fn parse_der_generalstring(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::GeneralString)
}
#[inline]
pub fn parse_der_bmpstring(i: &[u8]) -> IResult<&[u8], BerObject> {
parse_der_with_tag(i, BerTag::BmpString)
}
#[inline]
pub fn parse_der_explicit<F>(i: &[u8], tag: BerTag, f: F) -> IResult<&[u8], DerObject, u32>
where
F: Fn(&[u8]) -> IResult<&[u8], DerObject, u32>,
{
parse_ber_explicit(i, tag, f)
}
#[inline]
pub fn parse_der_implicit<F>(i: &[u8], tag: BerTag, f: F) -> IResult<&[u8], DerObject, u32>
where
F: Fn(&[u8], BerTag, usize) -> IResult<&[u8], BerObjectContent, u32>,
{
parse_ber_implicit(i, tag, f)
}
pub fn parse_der_u32(i: &[u8]) -> IResult<&[u8], u32> {
match parse_ber_integer(i) {
Ok((rem, ref obj)) => match obj.content {
BerObjectContent::Integer(i) => match i.len() {
1 => Ok((rem, i[0] as u32)),
2 => Ok((rem, (i[0] as u32) << 8 | (i[1] as u32))),
3 => Ok((
rem,
(i[0] as u32) << 16 | (i[1] as u32) << 8 | (i[2] as u32),
)),
4 => Ok((
rem,
(i[0] as u32) << 24 | (i[1] as u32) << 16 | (i[2] as u32) << 8 | (i[3] as u32),
)),
_ => Err(Err::Error(error_position!(
i,
ErrorKind::Custom(BER_INTEGER_TOO_LARGE)
))),
},
_ => Err(Err::Error(error_position!(
i,
ErrorKind::Custom(BER_TAG_ERROR)
))),
},
Err(e) => Err(e),
}
}
pub fn parse_der_u64(i: &[u8]) -> IResult<&[u8], u64> {
match parse_ber_integer(i) {
Ok((rem, ref obj)) => match obj.content {
BerObjectContent::Integer(i) => match bytes_to_u64(i) {
Ok(l) => Ok((rem, l)),
Err(_) => Err(Err::Error(error_position!(
i,
ErrorKind::Custom(BER_INTEGER_TOO_LARGE)
))),
},
_ => Err(Err::Error(error_position!(
i,
ErrorKind::Custom(BER_TAG_ERROR)
))),
},
Err(e) => Err(e),
}
}
pub fn der_read_element_content_as(
i: &[u8],
tag: BerTag,
len: usize,
constructed: bool,
depth: usize,
) -> IResult<&[u8], BerObjectContent> {
if i.len() < len {
return Err(Err::Incomplete(Needed::Size(len)));
}
match tag {
BerTag::Boolean => {
error_if!(i, len != 1, ErrorKind::Custom(BER_INVALID_LENGTH))?;
der_constraint_fail_if!(i, i[0] != 0 && i[0] != 0xff);
}
BerTag::BitString => {
der_constraint_fail_if!(i, constructed);
return der_read_content_bitstring(i, len);
}
BerTag::NumericString
| BerTag::PrintableString
| BerTag::Ia5String
| BerTag::Utf8String
| BerTag::T61String
| BerTag::BmpString
| BerTag::GeneralString => {
der_constraint_fail_if!(i, constructed);
}
BerTag::UtcTime | BerTag::GeneralizedTime => match i.last() {
Some(b'Z') => (),
_ => {
return Err(Err::Error(error_position!(
i,
ErrorKind::Custom(DER_CONSTRAINT_FAIL)
)));
}
},
_ => (),
}
ber_read_element_content_as(i, tag, len, constructed, depth)
}
pub fn der_read_element_content(i: &[u8], hdr: BerObjectHeader) -> IResult<&[u8], DerObject> {
match hdr.class {
0b00 |
0b11 => (),
0b01 |
0b10 => return map!(
i,
take!(hdr.len),
|b| { DerObject::from_header_and_content(hdr,BerObjectContent::Unknown(hdr.tag, b)) }
),
_ => { return Err(Err::Error(error_position!(i, ErrorKind::Custom(BER_CLASS_ERROR)))); },
}
match der_read_element_content_as(i, hdr.tag, hdr.len as usize, hdr.is_constructed(), 0) {
Ok((rem, content)) => Ok((rem, DerObject::from_header_and_content(hdr, content))),
Err(Err::Error(Context::Code(_, ErrorKind::Custom(BER_TAG_UNKNOWN)))) => {
map!(i, take!(hdr.len), |b| {
DerObject::from_header_and_content(hdr, BerObjectContent::Unknown(hdr.tag, b))
})
}
Err(e) => Err(e),
}
}
#[inline]
fn der_read_content_bitstring(i: &[u8], len: usize) -> IResult<&[u8], BerObjectContent> {
do_parse! {
i,
ignored_bits: be_u8 >>
error_if!(ignored_bits > 7, ErrorKind::Custom(DER_CONSTRAINT_FAIL)) >>
error_if!(len == 0, ErrorKind::Custom(BER_INVALID_LENGTH)) >>
s: take!(len - 1) >>
call!(|input| {
if len > 1 {
let mut last_byte = s[len-2];
for _ in 0..ignored_bits as usize {
der_constraint_fail_if!(i, last_byte & 1 != 0);
last_byte >>= 1;
}
}
Ok((input,()))
}) >>
( BerObjectContent::BitString(ignored_bits,BitStringObject{ data:s }) )
}
}
pub fn der_read_element_header(i: &[u8]) -> IResult<&[u8], BerObjectHeader> {
do_parse! {
i,
el: parse_identifier >>
len: parse_ber_length_byte >>
llen: cond!(len.0 == 1, take!(len.1)) >>
( {
let len : u64 = match len.0 {
0 => len.1 as u64,
_ => {
error_if!(&i[1..], len.1 == 0b0111_1111, ErrorKind::Custom(BER_INVALID_LENGTH))?;
der_constraint_fail_if!(&i[1..], len.1 == 0 && el.1 != 1);
let llen = llen.unwrap();
match bytes_to_u64(llen) {
Ok(l) => {
der_constraint_fail_if!(i, l < 127);
l
},
Err(_) => { return Err(::nom::Err::Error(error_position!(llen, ErrorKind::Custom(BER_TAG_ERROR)))); },
}
},
};
BerObjectHeader {
class: el.0,
structured: el.1,
tag: BerTag(el.2),
len,
}
} )
}
}