From 8c3ab7aa06484613869d6101b93059d937f4c473 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 4 May 2022 10:33:54 -0600 Subject: [PATCH] der: use `Reader<'a>` as input for `Decode::decode` Implements decoding generically in terms of the `Reader` trait, similar to what #611 did for encoding. This approach can enable 1-pass on-the-fly PEM decoding for `DecodeOwned` types (although that will require some additional work beyond what's in this PR). --- der/derive/src/asn1_type.rs | 14 +- der/derive/src/attributes.rs | 17 +- der/derive/src/choice.rs | 13 +- der/derive/src/choice/variant.rs | 8 +- der/derive/src/enumerated.rs | 11 +- der/derive/src/lib.rs | 10 +- der/derive/src/sequence.rs | 18 +- der/derive/src/sequence/field.rs | 8 +- der/src/arrayvec.rs | 19 +- der/src/asn1/any.rs | 9 +- der/src/asn1/bit_string.rs | 18 +- der/src/asn1/boolean.rs | 10 +- der/src/asn1/context_specific.rs | 56 +++--- der/src/asn1/generalized_time.rs | 26 +-- der/src/asn1/ia5_string.rs | 8 +- der/src/asn1/integer.rs | 12 +- der/src/asn1/integer/bigint.rs | 8 +- der/src/asn1/null.rs | 16 +- der/src/asn1/octet_string.rs | 8 +- der/src/asn1/oid.rs | 13 +- der/src/asn1/optional.rs | 8 +- der/src/asn1/printable_string.rs | 8 +- der/src/asn1/real.rs | 12 +- der/src/asn1/sequence.rs | 27 +-- der/src/asn1/sequence_of.rs | 58 +++--- der/src/asn1/set_of.rs | 50 +++-- der/src/asn1/utc_time.rs | 8 +- der/src/asn1/utf8_string.rs | 8 +- der/src/byte_slice.rs | 8 +- der/src/decode.rs | 24 +-- der/src/decoder.rs | 213 ++++------------------ der/src/document.rs | 9 +- der/src/header.rs | 10 +- der/src/length.rs | 18 +- der/src/lib.rs | 65 +++---- der/src/reader.rs | 103 +++++++++-- der/src/reader/nested.rs | 96 ++++++++++ der/src/str_slice.rs | 6 +- der/src/tag.rs | 8 +- der/src/writer.rs | 6 +- pkcs1/src/private_key.rs | 34 ++-- pkcs1/src/private_key/other_prime_info.rs | 14 +- pkcs1/src/public_key.rs | 12 +- pkcs1/src/version.rs | 6 +- pkcs5/src/lib.rs | 8 +- pkcs5/src/pbes1.rs | 27 ++- pkcs5/src/pbes2.rs | 10 +- pkcs5/src/pbes2/kdf.rs | 50 +++-- pkcs7/src/content_info.rs | 17 +- pkcs7/src/content_type.rs | 74 ++++---- pkcs7/src/data_content.rs | 8 +- pkcs7/src/encrypted_data_content.rs | 20 +- pkcs7/src/enveloped_data_content.rs | 17 +- pkcs7/tests/content_tests.rs | 9 +- pkcs8/src/encrypted_private_key_info.rs | 15 +- pkcs8/src/private_key_info.rs | 35 ++-- pkcs8/src/version.rs | 6 +- sec1/src/parameters.rs | 6 +- sec1/src/private_key.rs | 16 +- spki/src/algorithm.rs | 15 +- spki/src/spki.rs | 22 +-- ssh-key/src/reader.rs | 4 - x509/src/ext/pkix/name/ediparty.rs | 2 +- x509/src/ext/pkix/name/other.rs | 2 +- x509/src/macros.rs | 4 +- x509/tests/certificate.rs | 81 ++++---- x509/tests/pkix_extensions.rs | 5 +- 67 files changed, 785 insertions(+), 781 deletions(-) create mode 100644 der/src/reader/nested.rs diff --git a/der/derive/src/asn1_type.rs b/der/derive/src/asn1_type.rs index cd7b5c2f4..f5ceaf9ea 100644 --- a/der/derive/src/asn1_type.rs +++ b/der/derive/src/asn1_type.rs @@ -47,13 +47,13 @@ impl Asn1Type { /// Get a `der::Decoder` object for a particular ASN.1 type pub fn decoder(self) -> TokenStream { match self { - Asn1Type::BitString => quote!(decoder.bit_string()?), - Asn1Type::Ia5String => quote!(decoder.ia5_string()?), - Asn1Type::GeneralizedTime => quote!(decoder.generalized_time()?), - Asn1Type::OctetString => quote!(decoder.octet_string()?), - Asn1Type::PrintableString => quote!(decoder.printable_string()?), - Asn1Type::UtcTime => quote!(decoder.utc_time()?), - Asn1Type::Utf8String => quote!(decoder.utf8_string()?), + Asn1Type::BitString => quote!(::der::asn1::BitString::decode(reader)?), + Asn1Type::Ia5String => quote!(::der::asn1::Ia5String::decode(reader)?), + Asn1Type::GeneralizedTime => quote!(::der::asn1::GeneralizedTime::decode(reader)?), + Asn1Type::OctetString => quote!(::der::asn1::OctetString::decode(reader)?), + Asn1Type::PrintableString => quote!(::der::asn1::PrintableString::decode(reader)?), + Asn1Type::UtcTime => quote!(::der::asn1::UtcTime::decode(reader)?), + Asn1Type::Utf8String => quote!(::der::asn1::Utf8String::decode(reader)?), } } diff --git a/der/derive/src/attributes.rs b/der/derive/src/attributes.rs index 168423672..c765e190c 100644 --- a/der/derive/src/attributes.rs +++ b/der/derive/src/attributes.rs @@ -95,7 +95,6 @@ impl FieldAttrs { pub fn parse(attrs: &[Attribute], type_attrs: &TypeAttrs) -> Self { let mut asn1_type = None; let mut context_specific = None; - let mut default = None; let mut extensible = None; let mut optional = None; @@ -203,13 +202,13 @@ impl FieldAttrs { if self.extensible || self.is_optional() { quote! { ::der::asn1::ContextSpecific::<#type_params>::decode_explicit( - decoder, + reader, #tag_number )? } } else { quote! { - match ::der::asn1::ContextSpecific::<#type_params>::decode(decoder)? { + match ::der::asn1::ContextSpecific::<#type_params>::decode(reader)? { field if field.tag_number == #tag_number => Some(field), _ => None } @@ -219,7 +218,7 @@ impl FieldAttrs { TagMode::Implicit => { quote! { ::der::asn1::ContextSpecific::<#type_params>::decode_implicit( - decoder, + reader, #tag_number )? } @@ -246,13 +245,15 @@ impl FieldAttrs { } } else if let Some(default) = &self.default { let type_params = self.asn1_type.map(|ty| ty.type_path()).unwrap_or_default(); - self.asn1_type.map(|ty| ty.decoder()).unwrap_or_else( - || quote!(decoder.decode::>()?.unwrap_or_else(#default)), - ) + self.asn1_type.map(|ty| ty.decoder()).unwrap_or_else(|| { + quote! { + Option::<#type_params>::decode(reader)?.unwrap_or_else(#default), + } + }) } else { self.asn1_type .map(|ty| ty.decoder()) - .unwrap_or_else(|| quote!(decoder.decode()?)) + .unwrap_or_else(|| quote!(reader.decode()?)) } } diff --git a/der/derive/src/choice.rs b/der/derive/src/choice.rs index 51c44163d..ac0dc37a7 100644 --- a/der/derive/src/choice.rs +++ b/der/derive/src/choice.rs @@ -5,7 +5,7 @@ mod variant; use self::variant::ChoiceVariant; -use crate::TypeAttrs; +use crate::{default_lifetime, TypeAttrs}; use proc_macro2::TokenStream; use proc_macro_error::abort; use quote::quote; @@ -59,10 +59,9 @@ impl DeriveChoice { pub fn to_tokens(&self) -> TokenStream { let ident = &self.ident; - // Explicit lifetime or `'_` let lifetime = match self.lifetime { Some(ref lifetime) => quote!(#lifetime), - None => quote!('_), + None => default_lifetime(), }; // Lifetime parameters @@ -88,16 +87,16 @@ impl DeriveChoice { } quote! { - impl<#lt_params> ::der::Choice<#lifetime> for #ident<#lt_params> { + impl<#lifetime> ::der::Choice<#lifetime> for #ident<#lt_params> { fn can_decode(tag: ::der::Tag) -> bool { matches!(tag, #(#can_decode_body)|*) } } - impl<#lt_params> ::der::Decode<#lifetime> for #ident<#lt_params> { - fn decode(decoder: &mut ::der::Decoder<#lifetime>) -> ::der::Result { + impl<#lifetime> ::der::Decode<#lifetime> for #ident<#lt_params> { + fn decode>(reader: &mut R) -> ::der::Result { use der::Reader as _; - match decoder.peek_tag()? { + match reader.peek_tag()? { #(#decode_body)* actual => Err(der::ErrorKind::TagUnexpected { expected: None, diff --git a/der/derive/src/choice/variant.rs b/der/derive/src/choice/variant.rs index 5132884be..650f3fa99 100644 --- a/der/derive/src/choice/variant.rs +++ b/der/derive/src/choice/variant.rs @@ -169,7 +169,7 @@ mod tests { variant.to_decode_tokens().to_string(), quote! { ::der::Tag::Utf8String => Ok(Self::ExampleVariant( - decoder.decode()? + reader.decode()? )), } .to_string() @@ -214,7 +214,7 @@ mod tests { variant.to_decode_tokens().to_string(), quote! { ::der::Tag::Utf8String => Ok(Self::ExampleVariant( - decoder.utf8_string()? + ::der::asn1::Utf8String::decode(reader)? .try_into()? )), } @@ -273,7 +273,7 @@ mod tests { constructed: #constructed, number: #tag_number, } => Ok(Self::ExplicitVariant( - match ::der::asn1::ContextSpecific::<>::decode(decoder)? { + match ::der::asn1::ContextSpecific::<>::decode(reader)? { field if field.tag_number == #tag_number => Some(field), _ => None } @@ -359,7 +359,7 @@ mod tests { number: #tag_number, } => Ok(Self::ImplicitVariant( ::der::asn1::ContextSpecific::<>::decode_implicit( - decoder, + reader, #tag_number )? .ok_or_else(|| { diff --git a/der/derive/src/enumerated.rs b/der/derive/src/enumerated.rs index a6db802fe..64db64aa4 100644 --- a/der/derive/src/enumerated.rs +++ b/der/derive/src/enumerated.rs @@ -2,7 +2,7 @@ //! the purposes of decoding/encoding ASN.1 `ENUMERATED` types as mapped to //! enum variants. -use crate::ATTR_NAME; +use crate::{default_lifetime, ATTR_NAME}; use proc_macro2::TokenStream; use proc_macro_error::abort; use quote::quote; @@ -102,6 +102,7 @@ impl DeriveEnumerated { /// Lower the derived output into a [`TokenStream`]. pub fn to_tokens(&self) -> TokenStream { + let default_lifetime = default_lifetime(); let ident = &self.ident; let repr = &self.repr; let tag = match self.integer { @@ -115,12 +116,12 @@ impl DeriveEnumerated { } quote! { - impl ::der::DecodeValue<'_> for #ident { - fn decode_value( - decoder: &mut ::der::Decoder<'_>, + impl<#default_lifetime> ::der::DecodeValue<#default_lifetime> for #ident { + fn decode_value>( + reader: &mut R, header: ::der::Header ) -> ::der::Result { - <#repr as ::der::DecodeValue>::decode_value(decoder, header)?.try_into() + <#repr as ::der::DecodeValue>::decode_value(reader, header)?.try_into() } } diff --git a/der/derive/src/lib.rs b/der/derive/src/lib.rs index c3e2414c9..023582049 100644 --- a/der/derive/src/lib.rs +++ b/der/derive/src/lib.rs @@ -134,8 +134,16 @@ use crate::{ value_ord::DeriveValueOrd, }; use proc_macro::TokenStream; +use proc_macro2::Span; use proc_macro_error::proc_macro_error; -use syn::{parse_macro_input, DeriveInput}; +use quote::quote; +use syn::{parse_macro_input, DeriveInput, Lifetime}; + +/// Get the default lifetime. +fn default_lifetime() -> proc_macro2::TokenStream { + let lifetime = Lifetime::new("'__der_lifetime", Span::call_site()); + quote!(#lifetime) +} /// Derive the [`Choice`][1] trait on an `enum`. /// diff --git a/der/derive/src/sequence.rs b/der/derive/src/sequence.rs index fb3db46e6..3e4724691 100644 --- a/der/derive/src/sequence.rs +++ b/der/derive/src/sequence.rs @@ -3,7 +3,7 @@ mod field; -use crate::TypeAttrs; +use crate::{default_lifetime, TypeAttrs}; use field::SequenceField; use proc_macro2::TokenStream; use proc_macro_error::abort; @@ -59,10 +59,9 @@ impl DeriveSequence { pub fn to_tokens(&self) -> TokenStream { let ident = &self.ident; - // Explicit lifetime or `'_` let lifetime = match self.lifetime { Some(ref lifetime) => quote!(#lifetime), - None => quote!('_), + None => default_lifetime(), }; // Lifetime parameters @@ -84,13 +83,14 @@ impl DeriveSequence { } quote! { - impl<#lt_params> ::der::DecodeValue<#lifetime> for #ident<#lt_params> { - fn decode_value( - decoder: &mut ::der::Decoder<#lifetime>, + impl<#lifetime> ::der::DecodeValue<#lifetime> for #ident<#lt_params> { + fn decode_value>( + reader: &mut R, header: ::der::Header, ) -> ::der::Result { - use ::der::DecodeValue; - ::der::asn1::SequenceRef::decode_value(decoder, header)?.decode_body(|decoder| { + use ::der::{Decode as _, DecodeValue as _, Reader as _}; + + reader.read_nested(header.length, |reader| { #(#decode_body)* Ok(Self { @@ -100,7 +100,7 @@ impl DeriveSequence { } } - impl<#lt_params> ::der::Sequence<#lifetime> for #ident<#lt_params> { + impl<#lifetime> ::der::Sequence<#lifetime> for #ident<#lt_params> { fn fields(&self, f: F) -> ::der::Result where F: FnOnce(&[&dyn der::Encode]) -> ::der::Result, diff --git a/der/derive/src/sequence/field.rs b/der/derive/src/sequence/field.rs index 057496e5e..4f478f0ea 100644 --- a/der/derive/src/sequence/field.rs +++ b/der/derive/src/sequence/field.rs @@ -146,8 +146,8 @@ impl LowerFieldDecoder { /// Handle default value for a type. fn apply_default(&mut self, default: &Path, field_type: &Type) { self.decoder = quote! { - decoder.decode::>()?.unwrap_or_else(#default); - } + Option::<#field_type>::decode(reader)?.unwrap_or_else(#default); + }; } } @@ -287,7 +287,7 @@ mod tests { assert_eq!( field.to_decode_tokens().to_string(), quote! { - let example_field = decoder.decode()?; + let example_field = reader.decode()?; } .to_string() ); @@ -328,7 +328,7 @@ mod tests { field.to_decode_tokens().to_string(), quote! { let implicit_field = ::der::asn1::ContextSpecific::<>::decode_implicit( - decoder, + reader, ::der::TagNumber::N0 )? .ok_or_else(|| { diff --git a/der/src/arrayvec.rs b/der/src/arrayvec.rs index 6e86ae7d2..21f134196 100644 --- a/der/src/arrayvec.rs +++ b/der/src/arrayvec.rs @@ -66,22 +66,9 @@ impl ArrayVec { self.length.checked_sub(1).and_then(|n| self.get(n)) } - /// Try to convert this [`ArrayVec`] into a `[T; N]`. - /// - /// Returns `None` if the [`ArrayVec`] does not contain `N` elements. - pub fn try_into_array(self) -> Result<[T; N]> { - if self.length != N { - return Err(ErrorKind::Incomplete { - expected_len: N.try_into()?, - actual_len: self.length.try_into()?, - } - .into()); - } - - Ok(self.elements.map(|elem| match elem { - Some(e) => e, - None => unreachable!(), - })) + /// Extract the inner array. + pub fn into_array(self) -> [Option; N] { + self.elements } } diff --git a/der/src/asn1/any.rs b/der/src/asn1/any.rs index 491cd84cf..74daae8c1 100644 --- a/der/src/asn1/any.rs +++ b/der/src/asn1/any.rs @@ -2,7 +2,7 @@ use crate::{ asn1::*, ByteSlice, Choice, Decode, DecodeValue, Decoder, DerOrd, EncodeValue, Error, - ErrorKind, FixedTag, Header, Length, Result, Tag, Tagged, ValueOrd, Writer, + ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Tagged, ValueOrd, Writer, }; use core::cmp::Ordering; @@ -153,11 +153,12 @@ impl<'a> Choice<'a> for Any<'a> { } impl<'a> Decode<'a> for Any<'a> { - fn decode(decoder: &mut Decoder<'a>) -> Result> { - let header = Header::decode(decoder)?; + fn decode>(reader: &mut R) -> Result> { + let header = Header::decode(reader)?; + Ok(Self { tag: header.tag, - value: ByteSlice::decode_value(decoder, header)?, + value: ByteSlice::decode_value(reader, header)?, }) } } diff --git a/der/src/asn1/bit_string.rs b/der/src/asn1/bit_string.rs index b8372ddb6..7ec1034c3 100644 --- a/der/src/asn1/bit_string.rs +++ b/der/src/asn1/bit_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `BIT STRING` support. use crate::{ - asn1::Any, ByteSlice, DecodeValue, Decoder, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, - Header, Length, Reader, Result, Tag, ValueOrd, Writer, + asn1::Any, ByteSlice, DecodeValue, DerOrd, EncodeValue, Error, ErrorKind, FixedTag, Header, + Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::{cmp::Ordering, iter::FusedIterator}; @@ -116,14 +116,14 @@ impl<'a> BitString<'a> { } impl<'a> DecodeValue<'a> for BitString<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { + fn decode_value>(reader: &mut R, header: Header) -> Result { let header = Header { tag: header.tag, length: (header.length - Length::ONE)?, }; - let unused_bits = decoder.read_byte()?; - let inner = ByteSlice::decode_value(decoder, header)?; + let unused_bits = reader.read_byte()?; + let inner = ByteSlice::decode_value(reader, header)?; Self::new(unused_bits, inner.as_slice()) } } @@ -239,12 +239,12 @@ where T::Type: From, T::Type: core::ops::Shl, { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let position = decoder.position(); - - let bits = BitString::decode_value(decoder, header)?; + fn decode_value>(reader: &mut R, header: Header) -> Result { + let position = reader.position(); + let bits = BitString::decode_value(reader, header)?; let mut flags = T::none().bits(); + if bits.bit_len() > core::mem::size_of_val(&flags) * 8 { return Err(Error::new(ErrorKind::Overlength, position)); } diff --git a/der/src/asn1/boolean.rs b/der/src/asn1/boolean.rs index 0bc16a53f..4de15f9d5 100644 --- a/der/src/asn1/boolean.rs +++ b/der/src/asn1/boolean.rs @@ -1,8 +1,8 @@ //! ASN.1 `BOOLEAN` support. use crate::{ - asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, ErrorKind, - FixedTag, Header, Length, Reader, Result, Tag, Writer, + asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, + Header, Length, Reader, Result, Tag, Writer, }; /// Byte used to encode `true` in ASN.1 DER. From X.690 Section 11.1: @@ -15,12 +15,12 @@ const TRUE_OCTET: u8 = 0b11111111; const FALSE_OCTET: u8 = 0b00000000; impl<'a> DecodeValue<'a> for bool { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { + fn decode_value>(reader: &mut R, header: Header) -> Result { if header.length != Length::ONE { - return Err(decoder.error(ErrorKind::Length { tag: Self::TAG })); + return Err(reader.error(ErrorKind::Length { tag: Self::TAG })); } - match decoder.read_byte()? { + match reader.read_byte()? { FALSE_OCTET => Ok(false), TRUE_OCTET => Ok(true), _ => Err(Self::TAG.non_canonical_error()), diff --git a/der/src/asn1/context_specific.rs b/der/src/asn1/context_specific.rs index dbc08045b..aab330d6b 100644 --- a/der/src/asn1/context_specific.rs +++ b/der/src/asn1/context_specific.rs @@ -1,8 +1,8 @@ //! Context-specific field. use crate::{ - asn1::Any, Choice, Decode, DecodeValue, Decoder, DerOrd, Encode, EncodeValue, EncodeValueRef, - Error, Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, + asn1::Any, Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, EncodeValueRef, Error, + Header, Length, Reader, Result, Tag, TagMode, TagNumber, Tagged, ValueOrd, Writer, }; use core::cmp::Ordering; @@ -39,22 +39,14 @@ impl ContextSpecific { /// higher numbered field consumed as a follow-up. /// - Returns `Ok(None)` if anything other than a [`ContextSpecific`] field /// is encountered. - pub fn decode_explicit<'a>( - decoder: &mut Decoder<'a>, + pub fn decode_explicit<'a, R: Reader<'a>>( + reader: &mut R, tag_number: TagNumber, ) -> Result> where T: Decode<'a>, { - Self::decode_with(decoder, tag_number, |decoder| { - let any = Any::decode(decoder)?; - - if !any.tag().is_constructed() { - return Err(any.tag().non_canonical_error()); - } - - Self::try_from(any) - }) + Self::decode_with(reader, tag_number, |reader| Self::decode(reader)) } /// Attempt to decode an `IMPLICIT` ASN.1 `CONTEXT-SPECIFIC` field with the @@ -63,16 +55,16 @@ impl ContextSpecific { /// This method otherwise behaves the same as `decode_explicit`, /// but should be used in cases where the particular fields are `IMPLICIT` /// as opposed to `EXPLICIT`. - pub fn decode_implicit<'a>( - decoder: &mut Decoder<'a>, + pub fn decode_implicit<'a, R: Reader<'a>>( + reader: &mut R, tag_number: TagNumber, ) -> Result> where T: DecodeValue<'a> + Tagged, { - Self::decode_with(decoder, tag_number, |decoder| { - let header = Header::decode(decoder)?; - let value = T::decode_value(decoder, header)?; + Self::decode_with(reader, tag_number, |reader| { + let header = Header::decode(reader)?; + let value = T::decode_value(reader, header)?; if header.tag.is_constructed() != value.tag().is_constructed() { return Err(header.tag.non_canonical_error()); @@ -88,23 +80,23 @@ impl ContextSpecific { /// Attempt to decode a context-specific field with the given /// helper callback. - fn decode_with<'a, F>( - decoder: &mut Decoder<'a>, + fn decode_with<'a, F, R: Reader<'a>>( + reader: &mut R, tag_number: TagNumber, f: F, ) -> Result> where - F: FnOnce(&mut Decoder<'a>) -> Result, + F: FnOnce(&mut R) -> Result, { - while let Some(octet) = decoder.peek_byte() { + while let Some(octet) = reader.peek_byte() { let tag = Tag::try_from(octet)?; if !tag.is_context_specific() || (tag.number() > tag_number) { break; } else if tag.number() == tag_number { - return Some(f(decoder)).transpose(); + return Some(f(reader)).transpose(); } else { - decoder.any()?; + Any::decode(reader)?; } } @@ -125,8 +117,20 @@ impl<'a, T> Decode<'a> for ContextSpecific where T: Decode<'a>, { - fn decode(decoder: &mut Decoder<'a>) -> Result { - Any::decode(decoder)?.try_into() + fn decode>(reader: &mut R) -> Result { + let header = Header::decode(reader)?; + + match header.tag { + Tag::ContextSpecific { + number, + constructed: true, + } => Ok(Self { + tag_number: number, + tag_mode: TagMode::default(), + value: reader.read_nested(header.length, |reader| T::decode(reader))?, + }), + tag => Err(tag.unexpected_error(None)), + } } } diff --git a/der/src/asn1/generalized_time.rs b/der/src/asn1/generalized_time.rs index f436113e7..107986fea 100644 --- a/der/src/asn1/generalized_time.rs +++ b/der/src/asn1/generalized_time.rs @@ -4,7 +4,7 @@ use crate::{ asn1::Any, datetime::{self, DateTime}, ord::OrdIsValueOrd, - ByteSlice, DecodeValue, Decoder, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, + ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; use core::time::Duration; @@ -73,9 +73,9 @@ impl GeneralizedTime { } } -impl DecodeValue<'_> for GeneralizedTime { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - match *ByteSlice::decode_value(decoder, header)?.as_slice() { +impl<'a> DecodeValue<'a> for GeneralizedTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + match *ByteSlice::decode_value(reader, header)?.as_slice() { // RFC 5280 requires mandatory seconds and Z-normalized time zone [y1, y2, y3, y4, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { let year = u16::from(datetime::decode_decimal(Self::TAG, y1, y2)?) @@ -163,9 +163,9 @@ impl TryFrom> for GeneralizedTime { } } -impl DecodeValue<'_> for DateTime { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - Ok(GeneralizedTime::decode_value(decoder, header)?.into()) +impl<'a> DecodeValue<'a> for DateTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(GeneralizedTime::decode_value(reader, header)?.into()) } } @@ -187,9 +187,9 @@ impl OrdIsValueOrd for DateTime {} #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl DecodeValue<'_> for SystemTime { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - Ok(GeneralizedTime::decode_value(decoder, header)?.into()) +impl<'a> DecodeValue<'a> for SystemTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(GeneralizedTime::decode_value(reader, header)?.into()) } } @@ -263,9 +263,9 @@ impl OrdIsValueOrd for SystemTime {} #[cfg(feature = "time")] #[cfg_attr(docsrs, doc(cfg(feature = "time")))] -impl DecodeValue<'_> for PrimitiveDateTime { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - GeneralizedTime::decode_value(decoder, header)?.try_into() +impl<'a> DecodeValue<'a> for PrimitiveDateTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + GeneralizedTime::decode_value(reader, header)?.try_into() } } diff --git a/der/src/asn1/ia5_string.rs b/der/src/asn1/ia5_string.rs index fa8ccd015..64073a0e1 100644 --- a/der/src/asn1/ia5_string.rs +++ b/der/src/asn1/ia5_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `IA5String` support. use crate::{ - asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, FixedTag, - Header, Length, Result, StrSlice, Tag, Writer, + asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, + Length, Reader, Result, StrSlice, Tag, Writer, }; use core::{fmt, str}; @@ -74,8 +74,8 @@ impl AsRef<[u8]> for Ia5String<'_> { } impl<'a> DecodeValue<'a> for Ia5String<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - Self::new(ByteSlice::decode_value(decoder, header)?.as_slice()) + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) } } diff --git a/der/src/asn1/integer.rs b/der/src/asn1/integer.rs index 2d0dcd51e..84277bf62 100644 --- a/der/src/asn1/integer.rs +++ b/der/src/asn1/integer.rs @@ -5,8 +5,8 @@ pub(super) mod int; pub(super) mod uint; use crate::{ - asn1::Any, ByteSlice, DecodeValue, Decoder, EncodeValue, Encoder, Error, FixedTag, Header, - Length, Result, Tag, ValueOrd, Writer, + asn1::Any, ByteSlice, DecodeValue, EncodeValue, Encoder, Error, FixedTag, Header, Length, + Reader, Result, Tag, ValueOrd, Writer, }; use core::{cmp::Ordering, mem}; @@ -14,8 +14,8 @@ macro_rules! impl_int_encoding { ($($int:ty => $uint:ty),+) => { $( impl<'a> DecodeValue<'a> for $int { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let bytes = ByteSlice::decode_value(decoder, header)?.as_slice(); + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); let result = if is_highest_bit_set(bytes) { <$uint>::from_be_bytes(int::decode_to_array(bytes)?) as $int @@ -75,8 +75,8 @@ macro_rules! impl_uint_encoding { ($($uint:ty),+) => { $( impl<'a> DecodeValue<'a> for $uint { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let bytes = ByteSlice::decode_value(decoder, header)?.as_slice(); + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); let result = Self::from_be_bytes(uint::decode_to_array(bytes)?); // Ensure we compute the same encoded length as the original any value diff --git a/der/src/asn1/integer/bigint.rs b/der/src/asn1/integer/bigint.rs index 9fa81e2a1..9d47cb404 100644 --- a/der/src/asn1/integer/bigint.rs +++ b/der/src/asn1/integer/bigint.rs @@ -2,8 +2,8 @@ use super::uint; use crate::{ - asn1::Any, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, ErrorKind, FixedTag, Header, - Length, Result, Tag, Writer, + asn1::Any, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, + Reader, Result, Tag, Writer, }; /// "Big" unsigned ASN.1 `INTEGER` type. @@ -46,8 +46,8 @@ impl<'a> UIntBytes<'a> { } impl<'a> DecodeValue<'a> for UIntBytes<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let bytes = ByteSlice::decode_value(decoder, header)?.as_slice(); + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); let result = Self::new(uint::decode_to_slice(bytes)?)?; // Ensure we compute the same encoded length as the original any value. diff --git a/der/src/asn1/null.rs b/der/src/asn1/null.rs index 41fd3473e..7f8a5263a 100644 --- a/der/src/asn1/null.rs +++ b/der/src/asn1/null.rs @@ -1,20 +1,20 @@ //! ASN.1 `NULL` support. use crate::{ - asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, ErrorKind, - FixedTag, Header, Length, Result, Tag, Writer, + asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, + Header, Length, Reader, Result, Tag, Writer, }; /// ASN.1 `NULL` type. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub struct Null; -impl DecodeValue<'_> for Null { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { +impl<'a> DecodeValue<'a> for Null { + fn decode_value>(reader: &mut R, header: Header) -> Result { if header.length.is_zero() { Ok(Null) } else { - Err(decoder.error(ErrorKind::Length { tag: Self::TAG })) + Err(reader.error(ErrorKind::Length { tag: Self::TAG })) } } } @@ -63,9 +63,9 @@ impl<'a> From<()> for Any<'a> { } } -impl DecodeValue<'_> for () { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - Null::decode_value(decoder, header)?; +impl<'a> DecodeValue<'a> for () { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Null::decode_value(reader, header)?; Ok(()) } } diff --git a/der/src/asn1/octet_string.rs b/der/src/asn1/octet_string.rs index 670e0a19b..498a4549b 100644 --- a/der/src/asn1/octet_string.rs +++ b/der/src/asn1/octet_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `OCTET STRING` support. use crate::{ - asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, ErrorKind, - FixedTag, Header, Length, Result, Tag, Writer, + asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, + Header, Length, Reader, Result, Tag, Writer, }; /// ASN.1 `OCTET STRING` type. @@ -43,8 +43,8 @@ impl AsRef<[u8]> for OctetString<'_> { } impl<'a> DecodeValue<'a> for OctetString<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let inner = ByteSlice::decode_value(decoder, header)?; + fn decode_value>(reader: &mut R, header: Header) -> Result { + let inner = ByteSlice::decode_value(reader, header)?; Ok(Self { inner }) } } diff --git a/der/src/asn1/oid.rs b/der/src/asn1/oid.rs index d17fd2bbd..7faacef04 100644 --- a/der/src/asn1/oid.rs +++ b/der/src/asn1/oid.rs @@ -1,15 +1,16 @@ //! ASN.1 `OBJECT IDENTIFIER` use crate::{ - asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, FixedTag, - Header, Length, Result, Tag, Tagged, Writer, + asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, + Length, Reader, Result, Tag, Tagged, Writer, }; use const_oid::ObjectIdentifier; -impl DecodeValue<'_> for ObjectIdentifier { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - let bytes = ByteSlice::decode_value(decoder, header)?.as_slice(); - Ok(Self::from_bytes(bytes)?) +impl<'a> DecodeValue<'a> for ObjectIdentifier { + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(Self::from_bytes( + ByteSlice::decode_value(reader, header)?.as_ref(), + )?) } } diff --git a/der/src/asn1/optional.rs b/der/src/asn1/optional.rs index e114a4f6a..a9b923ccc 100644 --- a/der/src/asn1/optional.rs +++ b/der/src/asn1/optional.rs @@ -1,16 +1,16 @@ //! ASN.1 `OPTIONAL` as mapped to Rust's `Option` type -use crate::{Choice, Decode, Decoder, DerOrd, Encode, Length, Reader, Result, Tag, Writer}; +use crate::{Choice, Decode, DerOrd, Encode, Length, Reader, Result, Tag, Writer}; use core::cmp::Ordering; impl<'a, T> Decode<'a> for Option where T: Choice<'a>, // NOTE: all `Decode + Tagged` types receive a blanket `Choice` impl { - fn decode(decoder: &mut Decoder<'a>) -> Result> { - if let Some(byte) = decoder.peek_byte() { + fn decode>(reader: &mut R) -> Result> { + if let Some(byte) = reader.peek_byte() { if T::can_decode(Tag::try_from(byte)?) { - return T::decode(decoder).map(Some); + return T::decode(reader).map(Some); } } diff --git a/der/src/asn1/printable_string.rs b/der/src/asn1/printable_string.rs index 5e74c8b69..be627a0d2 100644 --- a/der/src/asn1/printable_string.rs +++ b/der/src/asn1/printable_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `PrintableString` support. use crate::{ - asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, FixedTag, - Header, Length, Result, StrSlice, Tag, Writer, + asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, + Length, Reader, Result, StrSlice, Tag, Writer, }; use core::{fmt, str}; @@ -107,8 +107,8 @@ impl AsRef<[u8]> for PrintableString<'_> { } impl<'a> DecodeValue<'a> for PrintableString<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - Self::new(ByteSlice::decode_value(decoder, header)?.as_slice()) + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) } } diff --git a/der/src/asn1/real.rs b/der/src/asn1/real.rs index bd50f8ace..f872d2d0b 100644 --- a/der/src/asn1/real.rs +++ b/der/src/asn1/real.rs @@ -8,16 +8,16 @@ )] use crate::{ - str_slice::StrSlice, ByteSlice, DecodeValue, Decoder, EncodeValue, FixedTag, Header, Length, + str_slice::StrSlice, ByteSlice, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; use super::integer::uint::strip_leading_zeroes; #[cfg_attr(docsrs, doc(cfg(feature = "real")))] -impl DecodeValue<'_> for f64 { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - let bytes = ByteSlice::decode_value(decoder, header)?.as_slice(); +impl<'a> DecodeValue<'a> for f64 { + fn decode_value>(reader: &mut R, header: Header) -> Result { + let bytes = ByteSlice::decode_value(reader, header)?.as_slice(); if header.length == Length::ZERO { Ok(0.0) @@ -99,6 +99,7 @@ impl EncodeValue for f64 { } else { // The length is that of the first octets plus those needed for the exponent plus those needed for the mantissa let (_sign, exponent, mantissa) = decode_f64(*self); + let exponent_len = if exponent == 0 { // Section 8.5.7.4: there must be at least one octet for exponent encoding // But, if the exponent is zero, it'll be skipped, so we make sure force it to 1 @@ -107,13 +108,14 @@ impl EncodeValue for f64 { let ebytes = exponent.to_be_bytes(); Length::try_from(strip_leading_zeroes(&ebytes).len())? }; + let mantissa_len = if mantissa == 0 { Length::ONE } else { let mbytes = mantissa.to_be_bytes(); - // encoded_len(&mbytes)? Length::try_from(strip_leading_zeroes(&mbytes).len())? }; + exponent_len + mantissa_len + Length::ONE } } diff --git a/der/src/asn1/sequence.rs b/der/src/asn1/sequence.rs index 8146a7e2d..0debdef53 100644 --- a/der/src/asn1/sequence.rs +++ b/der/src/asn1/sequence.rs @@ -2,8 +2,8 @@ //! `SEQUENCE`s to Rust structs. use crate::{ - ByteSlice, Decode, DecodeValue, Decoder, Encode, EncodeValue, FixedTag, Header, Length, Reader, - Result, Tag, Writer, + ByteSlice, Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Result, + Tag, Writer, }; /// ASN.1 `SEQUENCE` trait. @@ -57,28 +57,13 @@ where pub struct SequenceRef<'a> { /// Body of the `SEQUENCE`. body: ByteSlice<'a>, - - /// Offset location in the outer document where this `SEQUENCE` begins. - offset: Length, -} - -impl<'a> SequenceRef<'a> { - /// Decode the body of this sequence. - pub fn decode_body(&self, f: F) -> Result - where - F: FnOnce(&mut Decoder<'a>) -> Result, - { - let mut nested_decoder = Decoder::new_with_offset(self.body, self.offset); - let result = f(&mut nested_decoder)?; - nested_decoder.finish(result) - } } impl<'a> DecodeValue<'a> for SequenceRef<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let offset = decoder.position(); - let body = ByteSlice::decode_value(decoder, header)?; - Ok(Self { body, offset }) + fn decode_value>(reader: &mut R, header: Header) -> Result { + Ok(Self { + body: ByteSlice::decode_value(reader, header)?, + }) } } diff --git a/der/src/asn1/sequence_of.rs b/der/src/asn1/sequence_of.rs index ee330ae0e..6334d7197 100644 --- a/der/src/asn1/sequence_of.rs +++ b/der/src/asn1/sequence_of.rs @@ -1,8 +1,8 @@ //! ASN.1 `SEQUENCE OF` support. use crate::{ - arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, Decoder, DerOrd, Encode, EncodeValue, - ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, + arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, + Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::cmp::Ordering; @@ -66,19 +66,16 @@ impl<'a, T, const N: usize> DecodeValue<'a> for SequenceOf where T: Decode<'a>, { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let end_pos = (decoder.position() + header.length)?; - let mut sequence_of = Self::new(); + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut sequence_of = Self::new(); - while decoder.position() < end_pos { - sequence_of.add(decoder.decode()?)?; - } - - if decoder.position() != end_pos { - decoder.error(ErrorKind::Length { tag: Self::TAG }); - } + while !reader.is_finished() { + sequence_of.add(T::decode(reader)?)?; + } - Ok(sequence_of) + Ok(sequence_of) + }) } } @@ -134,10 +131,18 @@ impl<'a, T, const N: usize> DecodeValue<'a> for [T; N] where T: Decode<'a>, { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - SequenceOf::decode_value(decoder, header)? - .inner - .try_into_array() + fn decode_value>(reader: &mut R, header: Header) -> Result { + let sequence_of = SequenceOf::::decode_value(reader, header)?; + + // TODO(tarcieri): use `[T; N]::try_map` instead of `expect` when stable + if sequence_of.inner.len() == N { + Ok(sequence_of + .inner + .into_array() + .map(|elem| elem.expect("arrayvec length mismatch"))) + } else { + Err(Self::TAG.length_error()) + } } } @@ -178,19 +183,16 @@ impl<'a, T> DecodeValue<'a> for Vec where T: Decode<'a>, { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let end_pos = (decoder.position() + header.length)?; - let mut sequence_of = Self::new(); + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut sequence_of = Self::new(); - while decoder.position() < end_pos { - sequence_of.push(decoder.decode()?); - } - - if decoder.position() != end_pos { - decoder.error(ErrorKind::Length { tag: Self::TAG }); - } + while !reader.is_finished() { + sequence_of.push(T::decode(reader)?); + } - Ok(sequence_of) + Ok(sequence_of) + }) } } diff --git a/der/src/asn1/set_of.rs b/der/src/asn1/set_of.rs index 820bba179..b8c4b0da4 100644 --- a/der/src/asn1/set_of.rs +++ b/der/src/asn1/set_of.rs @@ -11,8 +11,8 @@ //! ensuring they'll be in the proper order if reserialized. use crate::{ - arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, Decoder, DerOrd, Encode, EncodeValue, - Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, + arrayvec, ord::iter_cmp, ArrayVec, Decode, DecodeValue, DerOrd, Encode, EncodeValue, Error, + ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd, Writer, }; use core::cmp::Ordering; @@ -95,21 +95,18 @@ impl<'a, T, const N: usize> DecodeValue<'a> for SetOf where T: Decode<'a> + DerOrd, { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let end_pos = (decoder.position() + header.length)?; - let mut result = Self::new(); + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut result = Self::new(); - while decoder.position() < end_pos { - result.inner.add(decoder.decode()?)?; - } - - if decoder.position() != end_pos { - decoder.error(ErrorKind::Length { tag: Self::TAG }); - } + while !reader.is_finished() { + result.inner.add(T::decode(reader)?)?; + } - der_sort(result.inner.as_mut())?; - validate(result.inner.as_ref())?; - Ok(result) + der_sort(result.inner.as_mut())?; + validate(result.inner.as_ref())?; + Ok(result) + }) } } @@ -284,21 +281,18 @@ impl<'a, T> DecodeValue<'a> for SetOfVec where T: Decode<'a> + DerOrd, { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - let end_pos = (decoder.position() + header.length)?; - let mut inner = Vec::new(); + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_nested(header.length, |reader| { + let mut inner = Vec::new(); - while decoder.position() < end_pos { - inner.push(decoder.decode()?); - } - - if decoder.position() != end_pos { - decoder.error(ErrorKind::Length { tag: Self::TAG }); - } + while !reader.is_finished() { + inner.push(T::decode(reader)?); + } - der_sort(inner.as_mut())?; - validate(inner.as_ref())?; - Ok(Self { inner }) + der_sort(inner.as_mut())?; + validate(inner.as_ref())?; + Ok(Self { inner }) + }) } } diff --git a/der/src/asn1/utc_time.rs b/der/src/asn1/utc_time.rs index d1572b50f..a90f4b96b 100644 --- a/der/src/asn1/utc_time.rs +++ b/der/src/asn1/utc_time.rs @@ -4,7 +4,7 @@ use crate::{ asn1::Any, datetime::{self, DateTime}, ord::OrdIsValueOrd, - ByteSlice, DecodeValue, Decoder, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, + ByteSlice, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, }; use core::time::Duration; @@ -79,9 +79,9 @@ impl UtcTime { } } -impl DecodeValue<'_> for UtcTime { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> Result { - match *ByteSlice::decode_value(decoder, header)?.as_slice() { +impl<'a> DecodeValue<'a> for UtcTime { + fn decode_value>(reader: &mut R, header: Header) -> Result { + match *ByteSlice::decode_value(reader, header)?.as_slice() { // RFC 5280 requires mandatory seconds and Z-normalized time zone [year1, year2, mon1, mon2, day1, day2, hour1, hour2, min1, min2, sec1, sec2, b'Z'] => { let year = u16::from(datetime::decode_decimal(Self::TAG, year1, year2)?); diff --git a/der/src/asn1/utf8_string.rs b/der/src/asn1/utf8_string.rs index b800a8d4e..17a6e3fdb 100644 --- a/der/src/asn1/utf8_string.rs +++ b/der/src/asn1/utf8_string.rs @@ -1,8 +1,8 @@ //! ASN.1 `UTF8String` support. use crate::{ - asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, Decoder, EncodeValue, Error, FixedTag, - Header, Length, Result, StrSlice, Tag, Writer, + asn1::Any, ord::OrdIsValueOrd, ByteSlice, DecodeValue, EncodeValue, Error, FixedTag, Header, + Length, Reader, Result, StrSlice, Tag, Writer, }; use core::{fmt, str}; @@ -70,8 +70,8 @@ impl AsRef<[u8]> for Utf8String<'_> { } impl<'a> DecodeValue<'a> for Utf8String<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - Self::new(ByteSlice::decode_value(decoder, header)?.as_slice()) + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::new(ByteSlice::decode_value(reader, header)?.as_slice()) } } diff --git a/der/src/byte_slice.rs b/der/src/byte_slice.rs index 976401d7d..00d46d0f1 100644 --- a/der/src/byte_slice.rs +++ b/der/src/byte_slice.rs @@ -2,8 +2,8 @@ //! library-level length limitation i.e. `Length::max()`. use crate::{ - str_slice::StrSlice, DecodeValue, Decoder, DerOrd, EncodeValue, Error, Header, Length, Reader, - Result, Writer, + str_slice::StrSlice, DecodeValue, DerOrd, EncodeValue, Error, Header, Length, Reader, Result, + Writer, }; use core::cmp::Ordering; @@ -56,8 +56,8 @@ impl AsRef<[u8]> for ByteSlice<'_> { } impl<'a> DecodeValue<'a> for ByteSlice<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - decoder.read_slice(header.length).and_then(Self::new) + fn decode_value>(reader: &mut R, header: Header) -> Result { + reader.read_slice(header.length).and_then(Self::new) } } diff --git a/der/src/decode.rs b/der/src/decode.rs index 74f1b7e3e..039297df4 100644 --- a/der/src/decode.rs +++ b/der/src/decode.rs @@ -1,6 +1,6 @@ //! Trait definition for [`Decode`]. -use crate::{Decoder, FixedTag, Header, Result}; +use crate::{Decoder, FixedTag, Header, Reader, Result}; #[cfg(feature = "pem")] use { @@ -15,15 +15,9 @@ use crate::{Length, Tag}; /// /// This trait provides the core abstraction upon which all decoding operations /// are based. -/// -/// # Blanket impl for `TryFrom` -/// -/// In almost all cases you do not need to impl this trait yourself, but rather -/// can instead impl `TryFrom, Error = Error>` and receive a blanket -/// impl of this trait. pub trait Decode<'a>: Sized { /// Attempt to decode this message using the provided decoder. - fn decode(decoder: &mut Decoder<'a>) -> Result; + fn decode>(decoder: &mut R) -> Result; /// Parse `Self` from the provided DER-encoded byte slice. fn from_der(bytes: &'a [u8]) -> Result { @@ -37,10 +31,10 @@ impl<'a, T> Decode<'a> for T where T: DecodeValue<'a> + FixedTag, { - fn decode(decoder: &mut Decoder<'a>) -> Result { - let header = Header::decode(decoder)?; + fn decode>(reader: &mut R) -> Result { + let header = Header::decode(reader)?; header.tag.assert_eq(T::TAG)?; - T::decode_value(decoder, header) + T::decode_value(reader, header) } } @@ -64,15 +58,15 @@ impl DecodeOwned for T where T: for<'a> Decode<'a> {} #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] pub trait DecodePem: DecodeOwned + PemLabel { /// Try to decode this type from PEM. - fn from_pem(pem: &str) -> Result; + fn from_pem(pem: impl AsRef<[u8]>) -> Result; } #[cfg(feature = "pem")] #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] impl DecodePem for T { - fn from_pem(pem: &str) -> Result { + fn from_pem(pem: impl AsRef<[u8]>) -> Result { // TODO(tarcieri): support for decoding directly from PEM (instead of two-pass) - let (label, mut der_bytes) = pem::decode_vec(pem.as_bytes())?; + let (label, mut der_bytes) = pem::decode_vec(pem.as_ref())?; Self::validate_pem_label(label)?; let result = T::from_der(&der_bytes); @@ -85,5 +79,5 @@ impl DecodePem for T { /// and [`Length`]. pub trait DecodeValue<'a>: Sized { /// Attempt to decode this message using the provided [`Decoder`]. - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result; + fn decode_value>(decoder: &mut R, header: Header) -> Result; } diff --git a/der/src/decoder.rs b/der/src/decoder.rs index cb684214e..71271e0da 100644 --- a/der/src/decoder.rs +++ b/der/src/decoder.rs @@ -1,9 +1,6 @@ //! DER decoder. -use crate::{ - asn1::*, ByteSlice, Choice, Decode, DecodeValue, Encode, Error, ErrorKind, FixedTag, Header, - Length, Reader, Result, Tag, TagMode, TagNumber, -}; +use crate::{ByteSlice, Decode, Error, ErrorKind, Header, Length, Reader, Result, Tag}; /// DER decoder. #[derive(Clone, Debug)] @@ -16,41 +13,15 @@ pub struct Decoder<'a> { /// Position within the decoded slice. position: Length, - - /// Offset where `bytes` occurs in the original ASN.1 DER document. - /// - /// Used for nested decoding. - offset: Length, } impl<'a> Decoder<'a> { /// Create a new decoder for the given byte slice. pub fn new(bytes: &'a [u8]) -> Result { - Ok(Self::new_with_offset(ByteSlice::new(bytes)?, Length::ZERO)) - } - - /// Create a new decoder where `bytes` begins at a specified offset within - /// an original ASN.1 DER document. - /// - /// This is used for calculating positions when decoding nested documents. - pub(crate) fn new_with_offset(bytes: ByteSlice<'a>, offset: Length) -> Self { - Self { - bytes, + Ok(Self { + bytes: ByteSlice::new(bytes)?, failed: false, position: Length::ZERO, - offset, - } - } - - /// Decode a value which impls the [`Decode`] trait. - pub fn decode>(&mut self) -> Result { - if self.is_failed() { - return Err(self.error(ErrorKind::Failed)); - } - - T::decode(self).map_err(|e| { - self.failed = true; - e.nested(self.position) }) } @@ -71,144 +42,6 @@ impl<'a> Decoder<'a> { self.failed } - /// Finish decoding, returning the given value if there is no - /// remaining data, or an error otherwise - pub fn finish(self, value: T) -> Result { - if self.is_failed() { - Err(ErrorKind::Failed.at(self.position)) - } else if !self.is_finished() { - Err(ErrorKind::TrailingData { - decoded: self.position, - remaining: self.remaining_len(), - } - .at(self.position)) - } else { - Ok(value) - } - } - - /// Attempt to decode an ASN.1 `ANY` value. - pub fn any(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an `OPTIONAL` ASN.1 `ANY` value. - pub fn any_optional(&mut self) -> Result>> { - self.decode() - } - - /// Attempt to decode ASN.1 `INTEGER` as `i8` - pub fn int8(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode ASN.1 `INTEGER` as `i16` - pub fn int16(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode unsigned ASN.1 `INTEGER` as `u8` - pub fn uint8(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode unsigned ASN.1 `INTEGER` as `u16` - pub fn uint16(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode an ASN.1 `INTEGER` as a [`UIntBytes`]. - #[cfg(feature = "bigint")] - #[cfg_attr(docsrs, doc(cfg(feature = "bigint")))] - pub fn uint_bytes(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an ASN.1 `BIT STRING`. - pub fn bit_string(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an ASN.1 `CONTEXT-SPECIFIC` field with the - /// provided [`TagNumber`]. - pub fn context_specific( - &mut self, - tag_number: TagNumber, - tag_mode: TagMode, - ) -> Result> - where - T: DecodeValue<'a> + FixedTag, - { - Ok(match tag_mode { - TagMode::Explicit => ContextSpecific::::decode_explicit(self, tag_number)?, - TagMode::Implicit => ContextSpecific::::decode_implicit(self, tag_number)?, - } - .map(|field| field.value)) - } - - /// Attempt to decode an ASN.1 `GeneralizedTime`. - pub fn generalized_time(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode an ASN.1 `IA5String`. - pub fn ia5_string(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an ASN.1 `NULL` value. - pub fn null(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode an ASN.1 `OCTET STRING`. - pub fn octet_string(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an ASN.1 `OBJECT IDENTIFIER`. - #[cfg(feature = "oid")] - #[cfg_attr(docsrs, doc(cfg(feature = "oid")))] - pub fn oid(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode an ASN.1 `OPTIONAL` value. - pub fn optional>(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an ASN.1 `PrintableString`. - pub fn printable_string(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an ASN.1 `UTCTime`. - pub fn utc_time(&mut self) -> Result { - self.decode() - } - - /// Attempt to decode an ASN.1 `UTF8String`. - pub fn utf8_string(&mut self) -> Result> { - self.decode() - } - - /// Attempt to decode an ASN.1 `SEQUENCE`, creating a new nested - /// [`Decoder`] and calling the provided argument with it. - pub fn sequence(&mut self, f: F) -> Result - where - F: FnOnce(&mut Decoder<'a>) -> Result, - { - SequenceRef::decode(self)?.decode_body(f) - } - - /// Obtain a slice of bytes contain a complete TLV production suitable for parsing later. - pub fn tlv_bytes(&mut self) -> Result<&'a [u8]> { - let header = self.peek_header()?; - let header_len = header.encoded_len()?; - self.read_slice((header_len + header.length)?) - } - /// Obtain the remaining bytes in this decoder from the current cursor /// position. fn remaining(&self) -> Result<&'a [u8]> { @@ -239,18 +72,14 @@ impl<'a> Reader<'a> for Decoder<'a> { } fn position(&self) -> Length { - self.position.saturating_add(self.offset) + self.position } - fn read_slice(&mut self, len: impl TryInto) -> Result<&'a [u8]> { + fn read_slice(&mut self, len: Length) -> Result<&'a [u8]> { if self.is_failed() { return Err(self.error(ErrorKind::Failed)); } - let len = len - .try_into() - .map_err(|_| self.error(ErrorKind::Overflow))?; - match self.remaining()?.get(..len.try_into()?) { Some(result) => { self.position = (self.position + len)?; @@ -263,6 +92,36 @@ impl<'a> Reader<'a> for Decoder<'a> { } } + fn decode>(&mut self) -> Result { + if self.is_failed() { + return Err(self.error(ErrorKind::Failed)); + } + + T::decode(self).map_err(|e| { + self.failed = true; + e.nested(self.position) + }) + } + + fn error(&mut self, kind: ErrorKind) -> Error { + self.failed = true; + kind.at(self.position) + } + + fn finish(self, value: T) -> Result { + if self.is_failed() { + Err(ErrorKind::Failed.at(self.position)) + } else if !self.is_finished() { + Err(ErrorKind::TrailingData { + decoded: self.position, + remaining: self.remaining_len(), + } + .at(self.position)) + } else { + Ok(value) + } + } + fn remaining_len(&self) -> Length { debug_assert!(self.position <= self.input_len()); self.input_len().saturating_sub(self.position) @@ -319,7 +178,7 @@ mod tests { #[test] fn trailing_data() { let mut decoder = Decoder::new(EXAMPLE_MSG).unwrap(); - let x = decoder.decode().unwrap(); + let x = i8::decode(&mut decoder).unwrap(); assert_eq!(42i8, x); let err = decoder.finish(x).err().unwrap(); diff --git a/der/src/document.rs b/der/src/document.rs index a3cd4c9c2..5c44103d5 100644 --- a/der/src/document.rs +++ b/der/src/document.rs @@ -148,11 +148,12 @@ impl Debug for Document { } } -impl Decode<'_> for Document { - fn decode(decoder: &mut Decoder<'_>) -> Result { - let header = decoder.peek_header()?; +impl<'a> Decode<'a> for Document { + fn decode>(reader: &mut R) -> Result { + let header = reader.peek_header()?; let length = (header.encoded_len()? + header.length)?; - let bytes = decoder.read_slice(length)?; + let bytes = reader.read_slice(length)?; + Ok(Self { der_bytes: bytes.into(), length, diff --git a/der/src/header.rs b/der/src/header.rs index 48a551dfc..ddb484ee7 100644 --- a/der/src/header.rs +++ b/der/src/header.rs @@ -1,6 +1,6 @@ //! ASN.1 DER headers. -use crate::{Decode, Decoder, DerOrd, Encode, ErrorKind, Length, Result, Tag, Writer}; +use crate::{Decode, DerOrd, Encode, ErrorKind, Length, Reader, Result, Tag, Writer}; use core::cmp::Ordering; /// ASN.1 DER headers: tag + length component of TLV-encoded values @@ -23,11 +23,11 @@ impl Header { } } -impl Decode<'_> for Header { - fn decode(decoder: &mut Decoder<'_>) -> Result
{ - let tag = Tag::decode(decoder)?; +impl<'a> Decode<'a> for Header { + fn decode>(reader: &mut R) -> Result
{ + let tag = Tag::decode(reader)?; - let length = Length::decode(decoder).map_err(|e| { + let length = Length::decode(reader).map_err(|e| { if e.kind() == ErrorKind::Overlength { ErrorKind::Length { tag }.into() } else { diff --git a/der/src/length.rs b/der/src/length.rs index f9533b280..fb6162bc8 100644 --- a/der/src/length.rs +++ b/der/src/length.rs @@ -1,6 +1,6 @@ //! Length calculations for encoded ASN.1 DER values -use crate::{Decode, Decoder, DerOrd, Encode, Encoder, Error, ErrorKind, Reader, Result, Writer}; +use crate::{Decode, DerOrd, Encode, Encoder, Error, ErrorKind, Reader, Result, Writer}; use core::{ cmp::Ordering, fmt, @@ -138,13 +138,7 @@ impl Sub for Length { fn sub(self, other: Length) -> Result { self.0 .checked_sub(other.0) - .ok_or_else(|| { - ErrorKind::Incomplete { - expected_len: other, - actual_len: self, - } - .into() - }) + .ok_or_else(|| ErrorKind::Overflow.into()) .and_then(TryInto::try_into) } } @@ -205,9 +199,9 @@ impl TryFrom for usize { } } -impl Decode<'_> for Length { - fn decode(decoder: &mut Decoder<'_>) -> Result { - match decoder.read_byte()? { +impl<'a> Decode<'a> for Length { + fn decode>(reader: &mut R) -> Result { + match reader.read_byte()? { // Note: per X.690 Section 8.1.3.6.1 the byte 0x80 encodes indefinite // lengths, which are not allowed in DER, so disallow that byte. len if len < 0x80 => Ok(len.into()), @@ -219,7 +213,7 @@ impl Decode<'_> for Length { let mut decoded_len = 0u32; for _ in 0..nbytes { decoded_len = decoded_len.checked_shl(8).ok_or(ErrorKind::Overflow)? - | u32::from(decoder.read_byte()?); + | u32::from(reader.read_byte()?); } let length = Length::try_from(decoded_len)?; diff --git a/der/src/lib.rs b/der/src/lib.rs index 929ef71db..2f2819e27 100644 --- a/der/src/lib.rs +++ b/der/src/lib.rs @@ -98,7 +98,7 @@ //! // "heapless" usage when the `alloc` feature is disabled. //! use der::{ //! asn1::{Any, ObjectIdentifier}, -//! Decode, Decoder, Encode, Sequence +//! DecodeValue, Decode, Decoder, Encode, Header, Reader, Sequence //! }; //! //! /// X.509 `AlgorithmIdentifier`. @@ -112,40 +112,35 @@ //! pub parameters: Option> //! } //! -//! impl<'a> Decode<'a> for AlgorithmIdentifier<'a> { -//! fn decode(decoder: &mut Decoder<'a>) -> der::Result { -//! // The `Decoder::sequence` method decodes an ASN.1 `SEQUENCE` tag -//! // and length then calls the provided `FnOnce` with a nested -//! // `der::Decoder` which can be used to decode it. -//! decoder.sequence(|decoder| { -//! // The `der::Decoder::Decode` method can be used to decode any -//! // type which impls the `Decode` trait, which is impl'd for -//! // all of the ASN.1 built-in types in the `der` crate. -//! // -//! // Note that if your struct's fields don't contain an ASN.1 -//! // built-in type specifically, there are also helper methods -//! // for all of the built-in types supported by this library -//! // which can be used to select a specific type. -//! // -//! // For example, another way of decoding this particular field, -//! // which contains an ASN.1 `OBJECT IDENTIFIER`, is by calling -//! // `decoder.oid()`. Similar methods are defined for other -//! // ASN.1 built-in types. -//! let algorithm = decoder.decode()?; -//! -//! // This field contains an ASN.1 `OPTIONAL` type. The `der` crate -//! // maps this directly to Rust's `Option` type and provides -//! // impls of the `Decode` and `Encode` traits for `Option`. -//! // To explicitly request an `OPTIONAL` type be decoded, use the -//! // `decoder.optional()` method. -//! let parameters = decoder.decode()?; -//! -//! // The value returned from the provided `FnOnce` will be -//! // returned from the `any.sequence(...)` call above. -//! // Note that the entire sequence body *MUST* be consumed -//! // or an error will be returned. -//! Ok(Self { algorithm, parameters }) -//! }) +//! impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> { +//! fn decode_value>(reader: &mut R, _header: Header) -> der::Result { +//! // The `der::Decoder::Decode` method can be used to decode any +//! // type which impls the `Decode` trait, which is impl'd for +//! // all of the ASN.1 built-in types in the `der` crate. +//! // +//! // Note that if your struct's fields don't contain an ASN.1 +//! // built-in type specifically, there are also helper methods +//! // for all of the built-in types supported by this library +//! // which can be used to select a specific type. +//! // +//! // For example, another way of decoding this particular field, +//! // which contains an ASN.1 `OBJECT IDENTIFIER`, is by calling +//! // `decoder.oid()`. Similar methods are defined for other +//! // ASN.1 built-in types. +//! let algorithm = reader.decode()?; +//! +//! // This field contains an ASN.1 `OPTIONAL` type. The `der` crate +//! // maps this directly to Rust's `Option` type and provides +//! // impls of the `Decode` and `Encode` traits for `Option`. +//! // To explicitly request an `OPTIONAL` type be decoded, use the +//! // `decoder.optional()` method. +//! let parameters = reader.decode()?; +//! +//! // The value returned from the provided `FnOnce` will be +//! // returned from the `any.sequence(...)` call above. +//! // Note that the entire sequence body *MUST* be consumed +//! // or an error will be returned. +//! Ok(Self { algorithm, parameters }) //! } //! } //! diff --git a/der/src/reader.rs b/der/src/reader.rs index c4c95968c..f9431c0b3 100644 --- a/der/src/reader.rs +++ b/der/src/reader.rs @@ -1,9 +1,16 @@ //! Reader trait. -use crate::{Error, Header, Length, Result, Tag}; +mod nested; + +pub(crate) use nested::NestedReader; + +use crate::{ + asn1::ContextSpecific, Decode, DecodeValue, Encode, Error, ErrorKind, FixedTag, Header, Length, + Result, Tag, TagMode, TagNumber, +}; /// Reader trait which reads DER-encoded input. -pub trait Reader<'i>: Clone + Sized { +pub trait Reader<'r>: Sized { /// Get the length of the input. fn input_len(&self) -> Length; @@ -19,11 +26,67 @@ pub trait Reader<'i>: Clone + Sized { /// Get the position within the buffer. fn position(&self) -> Length; + /// Attempt to read data borrowed directly from the input as a slice, + /// updating the internal cursor position. + /// + /// # Returns + /// - `Ok(slice)` on success + /// - `Err(ErrorKind::Incomplete)` if there is not enough data + /// - `Err(ErrorKind::Reader)` if the reader can't borrow from the input + fn read_slice(&mut self, len: Length) -> Result<&'r [u8]>; + + /// Attempt to decode an ASN.1 `CONTEXT-SPECIFIC` field with the + /// provided [`TagNumber`]. + fn context_specific(&mut self, tag_number: TagNumber, tag_mode: TagMode) -> Result> + where + T: DecodeValue<'r> + FixedTag, + { + Ok(match tag_mode { + TagMode::Explicit => ContextSpecific::::decode_explicit(self, tag_number)?, + TagMode::Implicit => ContextSpecific::::decode_implicit(self, tag_number)?, + } + .map(|field| field.value)) + } + + /// Decode a value which impls the [`Decode`] trait. + fn decode>(&mut self) -> Result { + T::decode(self).map_err(|e| e.nested(self.position())) + } + + /// Return an error with the given [`ErrorKind`], annotating it with + /// context about where the error occurred. + fn error(&mut self, kind: ErrorKind) -> Error { + kind.at(self.position()) + } + + /// Finish decoding, returning the given value if there is no + /// remaining data, or an error otherwise + fn finish(self, value: T) -> Result { + if !self.is_finished() { + Err(ErrorKind::TrailingData { + decoded: self.position(), + remaining: self.remaining_len(), + } + .at(self.position())) + } else { + Ok(value) + } + } + /// Have we read all of the input data? fn is_finished(&self) -> bool { self.remaining_len().is_zero() } + /// Offset within the original input stream. + /// + /// This is used for error reporting, and doesn't need to be overridden + /// by any reader implementations (except for the built-in `NestedReader`, + /// which consumes nested input messages) + fn offset(&self) -> Length { + self.position() + } + /// Peek at the next byte in the decoder and attempt to decode it as a /// [`Tag`] value. /// @@ -35,14 +98,12 @@ pub trait Reader<'i>: Clone + Sized { } } - /// Attempt to read data borrowed directly from the input as a slice, - /// updating the internal cursor position. - /// - /// # Returns - /// - `Ok(slice)` on success - /// - `Err(ErrorKind::Incomplete)` if there is not enough data - /// - `Err(ErrorKind::Reader)` if the reader can't borrow from the input - fn read_slice(&mut self, len: impl TryInto) -> Result<&'i [u8]>; + /// Read a single byte. + fn read_byte(&mut self) -> Result { + let mut buf = [0]; + self.read_into(&mut buf)?; + Ok(buf[0]) + } /// Attempt to read input data, writing it into the provided buffer, and /// returning a slice on success. @@ -51,16 +112,19 @@ pub trait Reader<'i>: Clone + Sized { /// - `Ok(slice)` if there is sufficient data /// - `Err(ErrorKind::Incomplete)` if there is not enough data fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> { - let input = self.read_slice(buf.len())?; + let input = self.read_slice(buf.len().try_into()?)?; buf.copy_from_slice(input); Ok(buf) } - /// Read a single byte. - fn read_byte(&mut self) -> Result { - let mut buf = [0]; - self.read_into(&mut buf)?; - Ok(buf[0]) + /// Read nested data of the given length. + fn read_nested<'n, T, F>(&'n mut self, len: Length, f: F) -> Result + where + F: FnOnce(&mut NestedReader<'n, Self>) -> Result, + { + let mut reader = NestedReader::new(self, len)?; + let ret = f(&mut reader)?; + reader.finish(ret) } /// Get the number of bytes still remaining in the buffer. @@ -68,4 +132,11 @@ pub trait Reader<'i>: Clone + Sized { debug_assert!(self.position() <= self.input_len()); self.input_len().saturating_sub(self.position()) } + + /// Obtain a slice of bytes contain a complete TLV production suitable for parsing later. + fn tlv_bytes(&mut self) -> Result<&'r [u8]> { + let header = self.peek_header()?; + let header_len = header.encoded_len()?; + self.read_slice((header_len + header.length)?) + } } diff --git a/der/src/reader/nested.rs b/der/src/reader/nested.rs new file mode 100644 index 000000000..40ede69ac --- /dev/null +++ b/der/src/reader/nested.rs @@ -0,0 +1,96 @@ +//! Reader type for consuming nested TLV records within a DER document. + +use crate::{reader::Reader, Error, ErrorKind, Header, Length, Result}; + +/// Reader type used by [`Reader::read_nested`]. +pub struct NestedReader<'i, R> { + /// Inner reader type. + inner: &'i mut R, + + /// Nested input length. + input_len: Length, + + /// Position within the nested input. + position: Length, +} + +impl<'i, 'r, R: Reader<'r>> NestedReader<'i, R> { + /// Create a new nested reader which can read the given [`Length`]. + pub(crate) fn new(inner: &'i mut R, len: Length) -> Result { + if len <= inner.remaining_len() { + Ok(Self { + inner, + input_len: len, + position: Length::ZERO, + }) + } else { + Err(ErrorKind::Incomplete { + expected_len: (inner.offset() + len)?, + actual_len: (inner.offset() + inner.remaining_len())?, + } + .at(inner.offset())) + } + } + + /// Move the position cursor the given length, returning an error if there + /// isn't enough remaining data in the nested input. + fn advance_position(&mut self, len: Length) -> Result<()> { + let new_position = (self.position + len)?; + + if new_position <= self.input_len { + self.position = new_position; + Ok(()) + } else { + Err(ErrorKind::Incomplete { + expected_len: (self.inner.offset() + len)?, + actual_len: (self.inner.offset() + self.remaining_len())?, + } + .at(self.inner.offset())) + } + } +} + +impl<'i, 'r, R: Reader<'r>> Reader<'r> for NestedReader<'i, R> { + fn input_len(&self) -> Length { + self.input_len + } + + fn peek_byte(&self) -> Option { + if self.is_finished() { + None + } else { + self.inner.peek_byte() + } + } + + fn peek_header(&self) -> Result
{ + if self.is_finished() { + Err(Error::incomplete(self.offset())) + } else { + // TODO(tarcieri): handle peeking past nested length + self.inner.peek_header() + } + } + + fn position(&self) -> Length { + self.position + } + + fn read_slice(&mut self, len: Length) -> Result<&'r [u8]> { + self.advance_position(len)?; + self.inner.read_slice(len) + } + + fn error(&mut self, kind: ErrorKind) -> Error { + self.inner.error(kind) + } + + fn offset(&self) -> Length { + self.inner.offset() + } + + fn read_into<'o>(&mut self, out: &'o mut [u8]) -> Result<&'o [u8]> { + self.advance_position(Length::try_from(out.len())?)?; + self.inner.read_into(out) + } +} diff --git a/der/src/str_slice.rs b/der/src/str_slice.rs index 4e911be43..0016e958b 100644 --- a/der/src/str_slice.rs +++ b/der/src/str_slice.rs @@ -1,7 +1,7 @@ //! Common handling for types backed by `str` slices with enforcement of a //! library-level length limitation i.e. `Length::max()`. -use crate::{ByteSlice, DecodeValue, Decoder, EncodeValue, Header, Length, Result, Writer}; +use crate::{ByteSlice, DecodeValue, EncodeValue, Header, Length, Reader, Result, Writer}; use core::str; /// String slice newtype which respects the [`Length::max`] limit. @@ -63,8 +63,8 @@ impl AsRef<[u8]> for StrSlice<'_> { } impl<'a> DecodeValue<'a> for StrSlice<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> Result { - Self::from_bytes(ByteSlice::decode_value(decoder, header)?.as_slice()) + fn decode_value>(reader: &mut R, header: Header) -> Result { + Self::from_bytes(ByteSlice::decode_value(reader, header)?.as_slice()) } } diff --git a/der/src/tag.rs b/der/src/tag.rs index f590b929f..4906abb7a 100644 --- a/der/src/tag.rs +++ b/der/src/tag.rs @@ -6,7 +6,7 @@ mod number; pub use self::{class::Class, mode::TagMode, number::TagNumber}; -use crate::{Decode, Decoder, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer}; +use crate::{Decode, DerOrd, Encode, Error, ErrorKind, Length, Reader, Result, Writer}; use core::{cmp::Ordering, fmt}; /// Indicator bit for constructed form encoding (i.e. vs primitive form) @@ -302,9 +302,9 @@ impl From<&Tag> for u8 { } } -impl Decode<'_> for Tag { - fn decode(decoder: &mut Decoder<'_>) -> Result { - decoder.read_byte().and_then(Self::try_from) +impl<'a> Decode<'a> for Tag { + fn decode>(reader: &mut R) -> Result { + reader.read_byte().and_then(Self::try_from) } } diff --git a/der/src/writer.rs b/der/src/writer.rs index 79cbc0662..637c9c262 100644 --- a/der/src/writer.rs +++ b/der/src/writer.rs @@ -22,18 +22,18 @@ pub trait Writer { /// `Writer` type which outputs PEM-encoded data. #[cfg(feature = "pem")] #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -pub struct PemWriter<'o>(pem::Encoder<'static, 'o>); +pub struct PemWriter<'w>(pem::Encoder<'static, 'w>); #[cfg(feature = "pem")] #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] -impl<'o> PemWriter<'o> { +impl<'w> PemWriter<'w> { /// Create a new PEM writer which outputs into the provided buffer. /// /// Uses the default 64-character line wrapping. pub fn new( type_label: &'static str, line_ending: pem::LineEnding, - out: &'o mut [u8], + out: &'w mut [u8], ) -> Result { Ok(Self(pem::Encoder::new(type_label, line_ending, out)?)) } diff --git a/pkcs1/src/private_key.rs b/pkcs1/src/private_key.rs index 5daad5ad8..4ebd51039 100644 --- a/pkcs1/src/private_key.rs +++ b/pkcs1/src/private_key.rs @@ -5,7 +5,7 @@ pub(crate) mod other_prime_info; use crate::{Error, Result, RsaPublicKey, Version}; use core::fmt; -use der::{asn1::UIntBytes, Decode, Decoder, Encode, Sequence, Tag}; +use der::{asn1::UIntBytes, Decode, DecodeValue, Encode, Header, Reader, Sequence, Tag}; #[cfg(feature = "alloc")] use {self::other_prime_info::OtherPrimeInfo, alloc::vec::Vec, der::SecretDocument}; @@ -89,26 +89,26 @@ impl<'a> RsaPrivateKey<'a> { } } -impl<'a> Decode<'a> for RsaPrivateKey<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.sequence(|decoder| { - let version = Version::decode(decoder)?; +impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, |reader| { + let version = Version::decode(reader)?; let result = Self { - modulus: decoder.decode()?, - public_exponent: decoder.decode()?, - private_exponent: decoder.decode()?, - prime1: decoder.decode()?, - prime2: decoder.decode()?, - exponent1: decoder.decode()?, - exponent2: decoder.decode()?, - coefficient: decoder.decode()?, - other_prime_infos: decoder.decode()?, + modulus: reader.decode()?, + public_exponent: reader.decode()?, + private_exponent: reader.decode()?, + prime1: reader.decode()?, + prime2: reader.decode()?, + exponent1: reader.decode()?, + exponent2: reader.decode()?, + coefficient: reader.decode()?, + other_prime_infos: reader.decode()?, }; // Ensure version is set correctly for two-prime vs multi-prime key. if version.is_multi() != result.other_prime_infos.is_some() { - return Err(decoder.error(der::ErrorKind::Value { tag: Tag::Integer })); + return Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer })); } Ok(result) @@ -203,10 +203,10 @@ pub struct OtherPrimeInfos<'a> { #[cfg(not(feature = "alloc"))] impl<'a> Decode<'a> for OtherPrimeInfos<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { + fn decode>(reader: &mut R) -> der::Result { // Placeholder decoder that always returns an error. // Use `Tag::Integer` to signal an unsupported version. - Err(decoder.error(der::ErrorKind::Value { tag: Tag::Integer })) + Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer })) } } diff --git a/pkcs1/src/private_key/other_prime_info.rs b/pkcs1/src/private_key/other_prime_info.rs index f25b7f865..d75b7a19b 100644 --- a/pkcs1/src/private_key/other_prime_info.rs +++ b/pkcs1/src/private_key/other_prime_info.rs @@ -1,6 +1,6 @@ //! PKCS#1 OtherPrimeInfo support. -use der::{asn1::UIntBytes, Decode, Decoder, Encode, Sequence}; +use der::{asn1::UIntBytes, DecodeValue, Encode, Header, Reader, Sequence}; /// PKCS#1 OtherPrimeInfo as defined in [RFC 8017 Appendix 1.2]. /// @@ -28,13 +28,13 @@ pub struct OtherPrimeInfo<'a> { pub coefficient: UIntBytes<'a>, } -impl<'a> Decode<'a> for OtherPrimeInfo<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.sequence(|decoder| { +impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, |reader| { Ok(Self { - prime: decoder.decode()?, - exponent: decoder.decode()?, - coefficient: decoder.decode()?, + prime: reader.decode()?, + exponent: reader.decode()?, + coefficient: reader.decode()?, }) }) } diff --git a/pkcs1/src/public_key.rs b/pkcs1/src/public_key.rs index e1d28cc27..85b1ee1f1 100644 --- a/pkcs1/src/public_key.rs +++ b/pkcs1/src/public_key.rs @@ -1,7 +1,7 @@ //! PKCS#1 RSA Public Keys. use crate::{Error, Result}; -use der::{asn1::UIntBytes, Decode, Decoder, Encode, Sequence}; +use der::{asn1::UIntBytes, Decode, DecodeValue, Encode, Header, Reader, Sequence}; #[cfg(feature = "alloc")] use der::Document; @@ -30,12 +30,12 @@ pub struct RsaPublicKey<'a> { pub public_exponent: UIntBytes<'a>, } -impl<'a> Decode<'a> for RsaPublicKey<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.sequence(|decoder| { +impl<'a> DecodeValue<'a> for RsaPublicKey<'a> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, |reader| { Ok(Self { - modulus: decoder.decode()?, - public_exponent: decoder.decode()?, + modulus: reader.decode()?, + public_exponent: reader.decode()?, }) }) } diff --git a/pkcs1/src/version.rs b/pkcs1/src/version.rs index 585ebccde..6b253e8ae 100644 --- a/pkcs1/src/version.rs +++ b/pkcs1/src/version.rs @@ -1,7 +1,7 @@ //! PKCS#1 version identifier. use crate::Error; -use der::{Decode, Decoder, Encode, FixedTag, Tag, Writer}; +use der::{Decode, Encode, FixedTag, Reader, Tag, Writer}; /// Version identifier for PKCS#1 documents as defined in /// [RFC 8017 Appendix 1.2]. @@ -51,8 +51,8 @@ impl TryFrom for Version { } } -impl Decode<'_> for Version { - fn decode(decoder: &mut Decoder<'_>) -> der::Result { +impl<'a> Decode<'a> for Version { + fn decode>(decoder: &mut R) -> der::Result { Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error()) } } diff --git a/pkcs5/src/lib.rs b/pkcs5/src/lib.rs index 582874687..2b45ba261 100644 --- a/pkcs5/src/lib.rs +++ b/pkcs5/src/lib.rs @@ -29,7 +29,7 @@ pub use crate::error::{Error, Result}; pub use der::{self, asn1::ObjectIdentifier}; pub use spki::AlgorithmIdentifier; -use der::{Decode, Decoder, Encode, Sequence, Tag}; +use der::{Decode, DecodeValue, Encode, Header, Reader, Sequence, Tag}; #[cfg(all(feature = "alloc", feature = "pbes2"))] use alloc::vec::Vec; @@ -135,9 +135,9 @@ impl<'a> EncryptionScheme<'a> { } } -impl<'a> Decode<'a> for EncryptionScheme<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - AlgorithmIdentifier::decode(decoder)?.try_into() +impl<'a> DecodeValue<'a> for EncryptionScheme<'a> { + fn decode_value>(decoder: &mut R, header: Header) -> der::Result { + AlgorithmIdentifier::decode_value(decoder, header)?.try_into() } } diff --git a/pkcs5/src/pbes1.rs b/pkcs5/src/pbes1.rs index c12a6131b..963693b24 100644 --- a/pkcs5/src/pbes1.rs +++ b/pkcs5/src/pbes1.rs @@ -5,7 +5,7 @@ use crate::AlgorithmIdentifier; use der::{ asn1::{Any, ObjectIdentifier, OctetString}, - Decode, Decoder, Encode, ErrorKind, Length, Sequence, Tag, Writer, + Decode, Encode, ErrorKind, Length, Reader, Sequence, Tag, Writer, }; /// `pbeWithMD2AndDES-CBC` Object Identifier (OID). @@ -66,8 +66,8 @@ impl Algorithm { } } -impl Decode<'_> for Algorithm { - fn decode(decoder: &mut Decoder<'_>) -> der::Result { +impl<'a> Decode<'a> for Algorithm { + fn decode>(decoder: &mut R) -> der::Result { AlgorithmIdentifier::decode(decoder)?.try_into() } } @@ -117,8 +117,8 @@ pub struct Parameters { pub iteration_count: u16, } -impl Decode<'_> for Parameters { - fn decode(decoder: &mut Decoder<'_>) -> der::Result { +impl<'a> Decode<'a> for Parameters { + fn decode>(decoder: &mut R) -> der::Result { Any::decode(decoder)?.try_into() } } @@ -136,18 +136,13 @@ impl TryFrom> for Parameters { type Error = der::Error; fn try_from(any: Any<'_>) -> der::Result { - any.sequence(|params| { - let salt = params - .octet_string()? - .as_bytes() - .try_into() - .map_err(|_| der::Tag::OctetString.value_error())?; - - let iteration_count = params.decode()?; - + any.sequence(|reader| { Ok(Parameters { - salt, - iteration_count, + salt: OctetString::decode(reader)? + .as_bytes() + .try_into() + .map_err(|_| der::Tag::OctetString.value_error())?, + iteration_count: reader.decode()?, }) }) } diff --git a/pkcs5/src/pbes2.rs b/pkcs5/src/pbes2.rs index 3a397051f..ab5e03376 100644 --- a/pkcs5/src/pbes2.rs +++ b/pkcs5/src/pbes2.rs @@ -15,7 +15,7 @@ pub use self::kdf::{ use crate::{AlgorithmIdentifier, Error, Result}; use der::{ asn1::{Any, ObjectIdentifier, OctetString}, - Decode, Decoder, Encode, ErrorKind, Length, Sequence, Tag, Writer, + Decode, Encode, ErrorKind, Length, Reader, Sequence, Tag, Writer, }; #[cfg(all(feature = "alloc", feature = "pbes2"))] @@ -201,8 +201,8 @@ impl<'a> Parameters<'a> { } impl<'a> Decode<'a> for Parameters<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.any()?.try_into() + fn decode>(reader: &mut R) -> der::Result { + Any::decode(reader)?.try_into() } } @@ -304,8 +304,8 @@ impl<'a> EncryptionScheme<'a> { } impl<'a> Decode<'a> for EncryptionScheme<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - AlgorithmIdentifier::decode(decoder).and_then(TryInto::try_into) + fn decode>(reader: &mut R) -> der::Result { + AlgorithmIdentifier::decode(reader).and_then(TryInto::try_into) } } diff --git a/pkcs5/src/pbes2/kdf.rs b/pkcs5/src/pbes2/kdf.rs index 8e2410e24..c6d9fe80d 100644 --- a/pkcs5/src/pbes2/kdf.rs +++ b/pkcs5/src/pbes2/kdf.rs @@ -3,7 +3,7 @@ use crate::{AlgorithmIdentifier, Error, Result}; use der::{ asn1::{Any, ObjectIdentifier, OctetString}, - Decode, Decoder, Encode, ErrorKind, Length, Sequence, Tag, Tagged, Writer, + Decode, Encode, ErrorKind, Length, Reader, Sequence, Tag, Tagged, Writer, }; /// Password-Based Key Derivation Function (PBKDF2) OID. @@ -99,8 +99,8 @@ impl<'a> Kdf<'a> { } impl<'a> Decode<'a> for Kdf<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - AlgorithmIdentifier::decode(decoder)?.try_into() + fn decode>(reader: &mut R) -> der::Result { + AlgorithmIdentifier::decode(reader)?.try_into() } } @@ -205,8 +205,8 @@ impl<'a> Pbkdf2Params<'a> { } impl<'a> Decode<'a> for Pbkdf2Params<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.any()?.try_into() + fn decode>(reader: &mut R) -> der::Result { + Any::decode(reader)?.try_into() } } @@ -236,18 +236,16 @@ impl<'a> TryFrom> for Pbkdf2Params<'a> { type Error = der::Error; fn try_from(any: Any<'a>) -> der::Result { - any.sequence(|params| { + any.sequence(|reader| { // TODO(tarcieri): support salt `CHOICE` w\ `AlgorithmIdentifier` - let salt = params.octet_string()?; - let iteration_count = params.decode()?; - let key_length = params.optional()?; - let prf: Option> = params.optional()?; - Ok(Self { - salt: salt.as_bytes(), - iteration_count, - key_length, - prf: prf.map(TryInto::try_into).transpose()?.unwrap_or_default(), + salt: OctetString::decode(reader)?.as_bytes(), + iteration_count: reader.decode()?, + key_length: reader.decode()?, + prf: Option::>::decode(reader)? + .map(TryInto::try_into) + .transpose()? + .unwrap_or_default(), }) }) } @@ -398,8 +396,8 @@ impl<'a> ScryptParams<'a> { } impl<'a> Decode<'a> for ScryptParams<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.any()?.try_into() + fn decode>(reader: &mut R) -> der::Result { + Any::decode(reader)?.try_into() } } @@ -422,19 +420,13 @@ impl<'a> TryFrom> for ScryptParams<'a> { type Error = der::Error; fn try_from(any: Any<'a>) -> der::Result { - any.sequence(|params| { - let salt = params.octet_string()?; - let cost_parameter = params.decode()?; - let block_size = params.decode()?; - let parallelization = params.decode()?; - let key_length = params.optional()?; - + any.sequence(|reader| { Ok(Self { - salt: salt.as_bytes(), - cost_parameter, - block_size, - parallelization, - key_length, + salt: OctetString::decode(reader)?.as_bytes(), + cost_parameter: reader.decode()?, + block_size: reader.decode()?, + parallelization: reader.decode()?, + key_length: reader.decode()?, }) }) } diff --git a/pkcs7/src/content_info.rs b/pkcs7/src/content_info.rs index 7edfab324..0a47df109 100644 --- a/pkcs7/src/content_info.rs +++ b/pkcs7/src/content_info.rs @@ -2,7 +2,7 @@ use crate::{data_content::DataContent, encrypted_data_content::EncryptedDataCont use der::{ asn1::{ContextSpecific, OctetString}, - Decode, Decoder, Encode, Sequence, TagMode, TagNumber, + DecodeValue, Encode, Header, Reader, Sequence, TagMode, TagNumber, }; const CONTENT_TAG: TagNumber = TagNumber::new(0); @@ -65,21 +65,20 @@ impl<'a> ContentInfo<'a> { } } -impl<'a> Decode<'a> for ContentInfo<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result> { - decoder.sequence(|decoder| { - let content_type = decoder.decode()?; +impl<'a> DecodeValue<'a> for ContentInfo<'a> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result> { + reader.read_nested(header.length, |reader| { + let content_type = reader.decode()?; match content_type { ContentType::Data => Ok(ContentInfo::Data( - decoder.context_specific::>(CONTENT_TAG, TagMode::Explicit)?, + reader.context_specific::>(CONTENT_TAG, TagMode::Explicit)?, )), ContentType::EncryptedData => Ok(ContentInfo::EncryptedData( - ContextSpecific::decode_explicit(decoder, CONTENT_TAG)? - .map(|field| field.value), + reader.context_specific(CONTENT_TAG, TagMode::Explicit)?, )), _ => Ok(ContentInfo::Other(( content_type, - decoder.context_specific::>(CONTENT_TAG, TagMode::Explicit)?, + reader.context_specific::>(CONTENT_TAG, TagMode::Explicit)?, ))), } }) diff --git a/pkcs7/src/content_type.rs b/pkcs7/src/content_type.rs index bf6f29226..b5cd25522 100644 --- a/pkcs7/src/content_type.rs +++ b/pkcs7/src/content_type.rs @@ -1,67 +1,73 @@ use der::asn1::ObjectIdentifier; -use der::{DecodeValue, Decoder, EncodeValue, ErrorKind, FixedTag, Header, Length, Tag, Writer}; +use der::{DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Tag, Writer}; /// Indicates the type of content. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] pub enum ContentType { /// Plain data content type Data, + /// Signed-data content type SignedData, + /// Enveloped-data content type EnvelopedData, + /// Signed-and-enveloped-data content type SignedAndEnvelopedData, + /// Digested-data content type DigestedData, + /// Encrypted-data content type EncryptedData, } -impl ContentType { - /// return OID for content type - pub fn to_oid(&self) -> ObjectIdentifier { - match self { - Self::Data => crate::PKCS_7_DATA_OID, - Self::SignedData => crate::PKCS_7_SIGNED_DATA_OID, - Self::EnvelopedData => crate::PKCS_7_ENVELOPED_DATA_OID, - Self::SignedAndEnvelopedData => crate::PKCS_7_SIGNED_AND_ENVELOPED_DATA_OID, - Self::DigestedData => crate::PKCS_7_DIGESTED_DATA_OID, - Self::EncryptedData => crate::PKCS_7_ENCRYPTED_DATA_OID, - } - } - - /// match content type to given OID - pub fn from_oid(oid: ObjectIdentifier) -> Option { - match oid { - crate::PKCS_7_DATA_OID => Some(Self::Data), - crate::PKCS_7_SIGNED_DATA_OID => Some(Self::SignedData), - crate::PKCS_7_ENVELOPED_DATA_OID => Some(Self::EnvelopedData), - crate::PKCS_7_SIGNED_AND_ENVELOPED_DATA_OID => Some(Self::SignedAndEnvelopedData), - crate::PKCS_7_DIGESTED_DATA_OID => Some(Self::DigestedData), - crate::PKCS_7_ENCRYPTED_DATA_OID => Some(Self::EncryptedData), - _ => None, - } - } -} - impl<'a> DecodeValue<'a> for ContentType { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> der::Result { - let oid = ObjectIdentifier::decode_value(decoder, header)?; - ContentType::from_oid(oid).ok_or_else(|| decoder.error(ErrorKind::OidUnknown { oid })) + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + ObjectIdentifier::decode_value(reader, header)?.try_into() } } impl EncodeValue for ContentType { fn value_len(&self) -> der::Result { - self.to_oid().value_len() + ObjectIdentifier::from(*self).value_len() } fn encode_value(&self, writer: &mut dyn Writer) -> der::Result<()> { - self.to_oid().encode_value(writer) + ObjectIdentifier::from(*self).encode_value(writer) } } impl FixedTag for ContentType { const TAG: Tag = Tag::ObjectIdentifier; } + +impl From for ObjectIdentifier { + fn from(content_type: ContentType) -> ObjectIdentifier { + match content_type { + ContentType::Data => crate::PKCS_7_DATA_OID, + ContentType::SignedData => crate::PKCS_7_SIGNED_DATA_OID, + ContentType::EnvelopedData => crate::PKCS_7_ENVELOPED_DATA_OID, + ContentType::SignedAndEnvelopedData => crate::PKCS_7_SIGNED_AND_ENVELOPED_DATA_OID, + ContentType::DigestedData => crate::PKCS_7_DIGESTED_DATA_OID, + ContentType::EncryptedData => crate::PKCS_7_ENCRYPTED_DATA_OID, + } + } +} + +impl TryFrom for ContentType { + type Error = der::Error; + + fn try_from(oid: ObjectIdentifier) -> der::Result { + match oid { + crate::PKCS_7_DATA_OID => Ok(Self::Data), + crate::PKCS_7_SIGNED_DATA_OID => Ok(Self::SignedData), + crate::PKCS_7_ENVELOPED_DATA_OID => Ok(Self::EnvelopedData), + crate::PKCS_7_SIGNED_AND_ENVELOPED_DATA_OID => Ok(Self::SignedAndEnvelopedData), + crate::PKCS_7_DIGESTED_DATA_OID => Ok(Self::DigestedData), + crate::PKCS_7_ENCRYPTED_DATA_OID => Ok(Self::EncryptedData), + _ => Err(ErrorKind::OidUnknown { oid }.into()), + } + } +} diff --git a/pkcs7/src/data_content.rs b/pkcs7/src/data_content.rs index d6e98e5b6..9877bd24f 100644 --- a/pkcs7/src/data_content.rs +++ b/pkcs7/src/data_content.rs @@ -2,7 +2,7 @@ use core::convert::{From, TryFrom}; use der::{ - asn1::OctetString, DecodeValue, Decoder, EncodeValue, FixedTag, Header, Length, Tag, Writer, + asn1::OctetString, DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Tag, Writer, }; /// The content that is just an octet string. @@ -31,10 +31,8 @@ impl<'a> From> for &'a [u8] { } impl<'a> DecodeValue<'a> for DataContent<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> der::Result> { - Ok(OctetString::decode_value(decoder, header)? - .as_bytes() - .into()) + fn decode_value>(reader: &mut R, header: Header) -> der::Result> { + Ok(OctetString::decode_value(reader, header)?.as_bytes().into()) } } diff --git a/pkcs7/src/encrypted_data_content.rs b/pkcs7/src/encrypted_data_content.rs index 557a8a865..dda2c8dc2 100644 --- a/pkcs7/src/encrypted_data_content.rs +++ b/pkcs7/src/encrypted_data_content.rs @@ -2,8 +2,7 @@ use crate::enveloped_data_content::EncryptedContentInfo; use der::{ - Decode, DecodeValue, Decoder, Encode, EncodeValue, FixedTag, Header, Length, Sequence, Tag, - Writer, + DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence, Tag, Writer, }; /// Syntax version of the `encrypted-data` content type. @@ -41,8 +40,8 @@ impl TryFrom for Version { } impl<'a> DecodeValue<'a> for Version { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> der::Result { - Version::try_from(u8::decode_value(decoder, header)?) + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + Version::try_from(u8::decode_value(reader, header)?) } } @@ -82,12 +81,15 @@ pub struct EncryptedDataContent<'a> { pub encrypted_content_info: EncryptedContentInfo<'a>, } -impl<'a> Decode<'a> for EncryptedDataContent<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result> { - decoder.sequence(|decoder| { +impl<'a> DecodeValue<'a> for EncryptedDataContent<'a> { + fn decode_value>( + reader: &mut R, + header: Header, + ) -> der::Result> { + reader.read_nested(header.length, |reader| { Ok(EncryptedDataContent { - version: decoder.decode()?, - encrypted_content_info: decoder.decode()?, + version: reader.decode()?, + encrypted_content_info: reader.decode()?, }) }) } diff --git a/pkcs7/src/enveloped_data_content.rs b/pkcs7/src/enveloped_data_content.rs index 957189c6c..3cdd49e4d 100644 --- a/pkcs7/src/enveloped_data_content.rs +++ b/pkcs7/src/enveloped_data_content.rs @@ -4,7 +4,7 @@ use crate::ContentType; use der::{ asn1::{ContextSpecific, OctetString}, - Decode, Decoder, Encode, Sequence, TagMode, TagNumber, + DecodeValue, Encode, Header, Reader, Sequence, TagMode, TagNumber, }; use spki::AlgorithmIdentifier; @@ -49,13 +49,16 @@ pub struct EncryptedContentInfo<'a> { pub encrypted_content: Option<&'a [u8]>, } -impl<'a> Decode<'a> for EncryptedContentInfo<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result> { - decoder.sequence(|decoder| { +impl<'a> DecodeValue<'a> for EncryptedContentInfo<'a> { + fn decode_value>( + reader: &mut R, + header: Header, + ) -> der::Result> { + reader.read_nested(header.length, |reader| { Ok(EncryptedContentInfo { - content_type: decoder.decode()?, - content_encryption_algorithm: decoder.decode()?, - encrypted_content: decoder + content_type: reader.decode()?, + content_encryption_algorithm: reader.decode()?, + encrypted_content: reader .context_specific::>(ENCRYPTED_CONTENT_TAG, TagMode::Implicit)? .map(|o| o.as_bytes()), }) diff --git a/pkcs7/tests/content_tests.rs b/pkcs7/tests/content_tests.rs index d27b11f05..e923b1778 100644 --- a/pkcs7/tests/content_tests.rs +++ b/pkcs7/tests/content_tests.rs @@ -1,6 +1,9 @@ //! PKCS#7 example tests -use der::{asn1::ObjectIdentifier, Decode, Encoder}; +use der::{ + asn1::{ObjectIdentifier, OctetString}, + Decode, Encoder, +}; use hex_literal::hex; use pkcs7::{ encrypted_data_content::EncryptedDataContent, enveloped_data_content::EncryptedContentInfo, @@ -60,8 +63,8 @@ fn decode_encrypted_key_example() { let (salt, iter) = any .sequence(|decoder| { - let salt = decoder.octet_string()?; - let iter = decoder.uint16()?; + let salt = OctetString::decode(decoder)?; + let iter = u16::decode(decoder)?; Ok((salt, iter)) }) .expect("salt and iters parameters"); diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index 08babce09..c4336c9d9 100644 --- a/pkcs8/src/encrypted_private_key_info.rs +++ b/pkcs8/src/encrypted_private_key_info.rs @@ -2,7 +2,7 @@ use crate::{Error, Result}; use core::fmt; -use der::{asn1::OctetString, Decode, Decoder, Encode, Sequence}; +use der::{asn1::OctetString, Decode, DecodeValue, Encode, Header, Reader, Sequence}; use pkcs5::EncryptionScheme; #[cfg(feature = "alloc")] @@ -97,12 +97,15 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { } } -impl<'a> Decode<'a> for EncryptedPrivateKeyInfo<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result> { - decoder.sequence(|decoder| { +impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> { + fn decode_value>( + reader: &mut R, + header: Header, + ) -> der::Result> { + reader.read_nested(header.length, |reader| { Ok(Self { - encryption_algorithm: decoder.decode()?, - encrypted_data: decoder.octet_string()?.as_bytes(), + encryption_algorithm: reader.decode()?, + encrypted_data: OctetString::decode(reader)?.as_bytes(), }) }) } diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index d0ea3ec7c..06efb0d28 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -4,7 +4,7 @@ use crate::{AlgorithmIdentifier, Error, Result, Version}; use core::fmt; use der::{ asn1::{Any, BitString, ContextSpecific, OctetString}, - Decode, Decoder, Encode, Reader, Sequence, TagMode, TagNumber, + Decode, DecodeValue, Encode, Header, Reader, Sequence, TagMode, TagNumber, }; #[cfg(feature = "alloc")] @@ -158,14 +158,17 @@ impl<'a> PrivateKeyInfo<'a> { } } -impl<'a> Decode<'a> for PrivateKeyInfo<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result> { - decoder.sequence(|decoder| { +impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { + fn decode_value>( + reader: &mut R, + header: Header, + ) -> der::Result> { + reader.read_nested(header.length, |reader| { // Parse and validate `version` INTEGER. - let version = Version::decode(decoder)?; - let algorithm = decoder.decode()?; - let private_key = decoder.octet_string()?.into(); - let public_key = decoder + let version = Version::decode(reader)?; + let algorithm = reader.decode()?; + let private_key = OctetString::decode(reader)?.into(); + let public_key = reader .context_specific::>(PUBLIC_KEY_TAG, TagMode::Implicit)? .map(|bs| { bs.as_bytes() @@ -174,15 +177,19 @@ impl<'a> Decode<'a> for PrivateKeyInfo<'a> { .transpose()?; if version.has_public_key() != public_key.is_some() { - return Err(decoder.value_error(der::Tag::ContextSpecific { - constructed: true, - number: PUBLIC_KEY_TAG, - })); + return Err(reader.error( + der::Tag::ContextSpecific { + constructed: true, + number: PUBLIC_KEY_TAG, + } + .value_error() + .kind(), + )); } // Ignore any remaining extension fields - while !decoder.is_finished() { - decoder.decode::>>()?; + while !reader.is_finished() { + reader.decode::>>()?; } Ok(Self { diff --git a/pkcs8/src/version.rs b/pkcs8/src/version.rs index 09684782b..339368392 100644 --- a/pkcs8/src/version.rs +++ b/pkcs8/src/version.rs @@ -1,7 +1,7 @@ //! PKCS#8 version identifier. use crate::Error; -use der::{Decode, Decoder, Encode, FixedTag, Tag, Writer}; +use der::{Decode, Encode, FixedTag, Reader, Tag, Writer}; /// Version identifier for PKCS#8 documents. /// @@ -25,8 +25,8 @@ impl Version { } } -impl Decode<'_> for Version { - fn decode(decoder: &mut Decoder<'_>) -> der::Result { +impl<'a> Decode<'a> for Version { + fn decode>(decoder: &mut R) -> der::Result { Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error()) } } diff --git a/sec1/src/parameters.rs b/sec1/src/parameters.rs index 623cec3f0..001bc5aca 100644 --- a/sec1/src/parameters.rs +++ b/sec1/src/parameters.rs @@ -1,6 +1,6 @@ use der::{ asn1::{Any, ObjectIdentifier}, - DecodeValue, Decoder, EncodeValue, FixedTag, Header, Length, Tag, Writer, + DecodeValue, EncodeValue, FixedTag, Header, Length, Reader, Tag, Writer, }; /// Elliptic curve parameters as described in @@ -28,8 +28,8 @@ pub enum EcParameters { NamedCurve(ObjectIdentifier), } -impl DecodeValue<'_> for EcParameters { - fn decode_value(decoder: &mut Decoder<'_>, header: Header) -> der::Result { +impl<'a> DecodeValue<'a> for EcParameters { + fn decode_value>(decoder: &mut R, header: Header) -> der::Result { ObjectIdentifier::decode_value(decoder, header).map(Self::NamedCurve) } } diff --git a/sec1/src/private_key.rs b/sec1/src/private_key.rs index 0505b570d..e50a28c26 100644 --- a/sec1/src/private_key.rs +++ b/sec1/src/private_key.rs @@ -9,7 +9,7 @@ use crate::{EcParameters, Error, Result}; use core::fmt; use der::{ asn1::{BitString, ContextSpecific, OctetString}, - Decode, Decoder, Encode, Sequence, Tag, TagMode, TagNumber, + Decode, DecodeValue, Encode, Header, Reader, Sequence, Tag, TagMode, TagNumber, }; #[cfg(feature = "alloc")] @@ -70,16 +70,16 @@ pub struct EcPrivateKey<'a> { pub public_key: Option<&'a [u8]>, } -impl<'a> Decode<'a> for EcPrivateKey<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.sequence(|decoder| { - if decoder.uint8()? != VERSION { +impl<'a> DecodeValue<'a> for EcPrivateKey<'a> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, |reader| { + if u8::decode(reader)? != VERSION { return Err(der::Tag::Integer.value_error()); } - let private_key = decoder.octet_string()?.as_bytes(); - let parameters = decoder.context_specific(EC_PARAMETERS_TAG, TagMode::Explicit)?; - let public_key = decoder + let private_key = OctetString::decode(reader)?.as_bytes(); + let parameters = reader.context_specific(EC_PARAMETERS_TAG, TagMode::Explicit)?; + let public_key = reader .context_specific::>(PUBLIC_KEY_TAG, TagMode::Explicit)? .map(|bs| bs.as_bytes().ok_or_else(|| Tag::BitString.value_error())) .transpose()?; diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs index e2d73bf5e..116724239 100644 --- a/spki/src/algorithm.rs +++ b/spki/src/algorithm.rs @@ -2,8 +2,8 @@ use crate::{Error, Result}; use core::cmp::Ordering; -use der::asn1::{Any, ObjectIdentifier, SequenceRef}; -use der::{Decode, DecodeValue, Decoder, DerOrd, Encode, Header, Sequence, ValueOrd}; +use der::asn1::{Any, ObjectIdentifier}; +use der::{Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd}; /// X.509 `AlgorithmIdentifier` as defined in [RFC 5280 Section 4.1.1.2]. /// @@ -95,11 +95,12 @@ impl<'a> AlgorithmIdentifier<'a> { } impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> { - fn decode_value(decoder: &mut Decoder<'a>, header: Header) -> der::Result { - SequenceRef::decode_value(decoder, header)?.decode_body(|decoder| { - let oid = decoder.decode()?; - let parameters = decoder.decode()?; - Ok(Self { oid, parameters }) + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, |reader| { + Ok(Self { + oid: reader.decode()?, + parameters: reader.decode()?, + }) }) } } diff --git a/spki/src/spki.rs b/spki/src/spki.rs index c7961c309..e40cd668f 100644 --- a/spki/src/spki.rs +++ b/spki/src/spki.rs @@ -2,7 +2,9 @@ use crate::{AlgorithmIdentifier, Error, Result}; use core::cmp::Ordering; -use der::{asn1::BitString, Decode, Decoder, DerOrd, Encode, Sequence, ValueOrd}; +use der::{ + asn1::BitString, Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd, +}; #[cfg(feature = "alloc")] use der::Document; @@ -73,18 +75,14 @@ impl<'a> SubjectPublicKeyInfo<'a> { } } -impl<'a> Decode<'a> for SubjectPublicKeyInfo<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result { - decoder.sequence(|decoder| { - let algorithm = decoder.decode()?; - let subject_public_key = decoder - .bit_string()? - .as_bytes() - .ok_or_else(|| der::Tag::BitString.value_error())?; - +impl<'a> DecodeValue<'a> for SubjectPublicKeyInfo<'a> { + fn decode_value>(reader: &mut R, header: Header) -> der::Result { + reader.read_nested(header.length, |reader| { Ok(Self { - algorithm, - subject_public_key, + algorithm: reader.decode()?, + subject_public_key: BitString::decode(reader)? + .as_bytes() + .ok_or_else(|| der::Tag::BitString.value_error())?, }) }) } diff --git a/ssh-key/src/reader.rs b/ssh-key/src/reader.rs index dd4000b06..0f6245788 100644 --- a/ssh-key/src/reader.rs +++ b/ssh-key/src/reader.rs @@ -33,10 +33,6 @@ pub(crate) trait Reader: Sized { /// Decodes a `uint32` which identifies the length of some encapsulated /// data, then calls the given nested reader function with the length of /// the remaining data. - /// - /// As a postcondition, this function checks that the total amount of data - /// consumed matches the length prefix. - // TODO(tarcieri): enforce that data can't be read past the given length fn read_nested<'r, T, F>(&'r mut self, f: F) -> Result where F: FnOnce(&mut NestedReader<'r, Self>) -> Result, diff --git a/x509/src/ext/pkix/name/ediparty.rs b/x509/src/ext/pkix/name/ediparty.rs index 2ba65e1d0..06ee320b3 100644 --- a/x509/src/ext/pkix/name/ediparty.rs +++ b/x509/src/ext/pkix/name/ediparty.rs @@ -1,4 +1,4 @@ -use der::{Decode, Sequence}; +use der::Sequence; use super::DirectoryString; diff --git a/x509/src/ext/pkix/name/other.rs b/x509/src/ext/pkix/name/other.rs index 23b24de35..e81b2d140 100644 --- a/x509/src/ext/pkix/name/other.rs +++ b/x509/src/ext/pkix/name/other.rs @@ -1,4 +1,4 @@ -use der::{asn1::ObjectIdentifier, Any, Decode, Sequence}; +use der::{asn1::ObjectIdentifier, Any, Sequence}; /// OtherName as defined in [RFC 5280 Section 4.2.1.6]. /// diff --git a/x509/src/macros.rs b/x509/src/macros.rs index da0357049..2b7508ffe 100644 --- a/x509/src/macros.rs +++ b/x509/src/macros.rs @@ -40,8 +40,8 @@ macro_rules! impl_newtype { } impl<'a> ::der::DecodeValue<'a> for $newtype { - fn decode_value( - decoder: &mut ::der::Decoder<'a>, + fn decode_value>( + decoder: &mut R, header: ::der::Header, ) -> ::der::Result { Ok(Self(<$inner as ::der::DecodeValue>::decode_value( diff --git a/x509/tests/certificate.rs b/x509/tests/certificate.rs index 5ac0a347a..f1b5cb059 100644 --- a/x509/tests/certificate.rs +++ b/x509/tests/certificate.rs @@ -1,6 +1,9 @@ //! Certificate tests -use der::asn1::{BitString, ObjectIdentifier, UIntBytes}; -use der::{Decode, Decoder, Encode, Tag, Tagged}; + +use der::{ + asn1::{BitString, ContextSpecific, ObjectIdentifier, UIntBytes}, + Decode, DecodeValue, Encode, FixedTag, Header, Reader, Tag, Tagged, +}; use hex_literal::hex; use spki::AlgorithmIdentifier; use x509_cert::Certificate; @@ -30,23 +33,27 @@ pub struct DeferDecodeCertificate<'a> { pub signature: &'a [u8], } -impl<'a> Decode<'a> for DeferDecodeCertificate<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result> { - decoder.sequence(|decoder| { - let tbs_certificate = decoder.tlv_bytes()?; - let signature_algorithm = decoder.tlv_bytes()?; - let signature = decoder.tlv_bytes()?; +impl<'a> DecodeValue<'a> for DeferDecodeCertificate<'a> { + fn decode_value>( + reader: &mut R, + header: Header, + ) -> der::Result> { + reader.read_nested(header.length, |reader| { Ok(Self { - tbs_certificate, - signature_algorithm, - signature, + tbs_certificate: reader.tlv_bytes()?, + signature_algorithm: reader.tlv_bytes()?, + signature: reader.tlv_bytes()?, }) }) } } +impl FixedTag for DeferDecodeCertificate<'_> { + const TAG: Tag = Tag::Sequence; +} + ///Structure supporting deferred decoding of fields in the TBSCertificate SEQUENCE -pub struct DeferDecodeTBSCertificate<'a> { +pub struct DeferDecodeTbsCertificate<'a> { /// Decoded field pub version: u8, /// Defer decoded field @@ -69,38 +76,36 @@ pub struct DeferDecodeTBSCertificate<'a> { pub extensions: &'a [u8], } -impl<'a> Decode<'a> for DeferDecodeTBSCertificate<'a> { - fn decode(decoder: &mut Decoder<'a>) -> der::Result> { - decoder.sequence(|decoder| { - let version = - ::der::asn1::ContextSpecific::decode_explicit(decoder, ::der::TagNumber::N0)? - .map(|cs| cs.value) - .unwrap_or_else(Default::default); - let serial_number = decoder.tlv_bytes()?; - let signature = decoder.tlv_bytes()?; - let issuer = decoder.tlv_bytes()?; - let validity = decoder.tlv_bytes()?; - let subject = decoder.tlv_bytes()?; - let subject_public_key_info = decoder.tlv_bytes()?; - let issuer_unique_id = decoder.decode()?; - let subject_unique_id = decoder.decode()?; - let extensions = decoder.tlv_bytes()?; +impl<'a> DecodeValue<'a> for DeferDecodeTbsCertificate<'a> { + fn decode_value>( + reader: &mut R, + header: Header, + ) -> der::Result> { + reader.read_nested(header.length, |reader| { + let version = ContextSpecific::decode_explicit(reader, ::der::TagNumber::N0)? + .map(|cs| cs.value) + .unwrap_or_else(Default::default); + Ok(Self { version, - serial_number, - signature, - issuer, - validity, - subject, - subject_public_key_info, - issuer_unique_id, - subject_unique_id, - extensions, + serial_number: reader.tlv_bytes()?, + signature: reader.tlv_bytes()?, + issuer: reader.tlv_bytes()?, + validity: reader.tlv_bytes()?, + subject: reader.tlv_bytes()?, + subject_public_key_info: reader.tlv_bytes()?, + issuer_unique_id: reader.decode()?, + subject_unique_id: reader.decode()?, + extensions: reader.tlv_bytes()?, }) }) } } +impl FixedTag for DeferDecodeTbsCertificate<'_> { + const TAG: Tag = Tag::Sequence; +} + #[test] fn reencode_cert() { let der_encoded_cert = @@ -120,7 +125,7 @@ fn reencode_cert() { assert_eq!(defer_cert.signature, reencoded_sig); let parsed_coverage_tbs = - DeferDecodeTBSCertificate::from_der(defer_cert.tbs_certificate).unwrap(); + DeferDecodeTbsCertificate::from_der(defer_cert.tbs_certificate).unwrap(); // TODO - defer decode then reencode version field diff --git a/x509/tests/pkix_extensions.rs b/x509/tests/pkix_extensions.rs index be227b45c..75613045d 100644 --- a/x509/tests/pkix_extensions.rs +++ b/x509/tests/pkix_extensions.rs @@ -1030,10 +1030,11 @@ fn decode_idp() { let idp = IssuingDistributionPoint::from_der(&hex!("3067A060A05EA45C305A310B3009060355040613025553311F301D060355040A131654657374204365727469666963617465732032303137311C301A060355040B13136F6E6C79536F6D65526561736F6E7320434133310C300A0603550403130343524C8304079F80")); let err = idp.err().unwrap(); + assert_eq!(err.position().unwrap(), 103u8.into()); assert_eq!( ErrorKind::Incomplete { - expected_len: 104u8.into(), - actual_len: 103u8.into() + expected_len: 106u8.into(), + actual_len: 105u8.into() }, err.kind() );