Skip to content

der: add Reader::read_value, auto-nest DecodeValue #1877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions der/src/asn1/internal_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ macro_rules! impl_custom_class {
return Err(header.tag.non_canonical_error().into());
}

// read_nested checks if header matches decoded length
let value = reader.read_nested(header.length, |reader| {
// read_value checks if header matches decoded length
let value = reader.read_value(header, |reader| {
// Decode inner IMPLICIT value
T::decode_value(reader, header)
})?;
Expand Down Expand Up @@ -192,7 +192,7 @@ macro_rules! impl_custom_class {
Tag::$class_enum_name { number, .. } => Ok(Self {
tag_number: number,
tag_mode: TagMode::default(),
value: reader.read_nested(header.length, |reader| {
value: reader.read_value(header, |reader| {
// Decode inner tag-length-value of EXPLICIT
T::decode(reader)
})?,
Expand Down
64 changes: 31 additions & 33 deletions der/src/asn1/sequence_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,14 @@ where
{
type Error = T::Error;

fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
reader.read_nested(header.length, |reader| {
let mut sequence_of = Self::new();
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> Result<Self, Self::Error> {
let mut sequence_of = Self::new();

while !reader.is_finished() {
sequence_of.add(T::decode(reader)?)?;
}
while !reader.is_finished() {
sequence_of.add(T::decode(reader)?)?;
}

Ok(sequence_of)
})
Ok(sequence_of)
}
}

Expand Down Expand Up @@ -133,6 +131,21 @@ impl<'a, T> Iterator for SequenceOfIter<'a, T> {

impl<T> ExactSizeIterator for SequenceOfIter<'_, T> {}

impl<T: Encode> EncodeValue for [T] {
fn value_len(&self) -> Result<Length, Error> {
self.iter()
.try_fold(Length::ZERO, |len, elem| len + elem.encoded_len()?)
}

fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
for elem in self {
elem.encode(writer)?;
}

Ok(())
}
}

impl<'a, T, const N: usize> DecodeValue<'a> for [T; N]
where
T: Decode<'a>,
Expand Down Expand Up @@ -164,11 +177,7 @@ where
}

fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
for elem in self {
elem.encode(writer)?;
}

Ok(())
self.as_slice().encode_value(writer)
}
}

Expand All @@ -185,28 +194,21 @@ where
}
}

#[cfg(feature = "alloc")]
fn decode_value_vec_inner<'a, T: Decode<'a>, R: Reader<'a>>(
reader: &mut R,
) -> Result<Vec<T>, T::Error> {
let mut sequence_of = Vec::<T>::new();

while !reader.is_finished() {
sequence_of.push(T::decode(reader)?);
}

Ok(sequence_of)
}

#[cfg(feature = "alloc")]
impl<'a, T> DecodeValue<'a> for Vec<T>
where
T: Decode<'a>,
{
type Error = T::Error;

fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
reader.read_nested(header.length, decode_value_vec_inner)
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> Result<Self, Self::Error> {
let mut sequence_of = Vec::<T>::new();

while !reader.is_finished() {
sequence_of.push(T::decode(reader)?);
}

Ok(sequence_of)
}
}

Expand All @@ -221,11 +223,7 @@ where
}

fn encode_value(&self, writer: &mut impl Writer) -> Result<(), Error> {
for elem in self {
elem.encode(writer)?;
}

Ok(())
self.as_slice().encode_value(writer)
}
}

Expand Down
34 changes: 15 additions & 19 deletions der/src/asn1/set_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,16 @@ where
{
type Error = T::Error;

fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
reader.read_nested(header.length, |reader| {
let mut result = Self::new();
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> Result<Self, Self::Error> {
let mut result = Self::new();

while !reader.is_finished() {
result.inner.push(T::decode(reader)?)?;
}
while !reader.is_finished() {
result.inner.push(T::decode(reader)?)?;
}

// Ensure elements of the `SetOf` are sorted and will serialize as valid DER
der_sort(result.inner.as_mut())?;
Ok(result)
})
// Ensure elements of the `SetOf` are sorted and will serialize as valid DER
der_sort(result.inner.as_mut())?;
Ok(result)
}
}

Expand Down Expand Up @@ -334,17 +332,15 @@ where
{
type Error = T::Error;

fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self, Self::Error> {
reader.read_nested(header.length, |reader| {
let mut inner = Vec::new();
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> Result<Self, Self::Error> {
let mut inner = Vec::new();

while !reader.is_finished() {
inner.push(T::decode(reader)?);
}
while !reader.is_finished() {
inner.push(T::decode(reader)?);
}

der_sort(inner.as_mut())?;
Ok(Self { inner })
})
der_sort(inner.as_mut())?;
Ok(Self { inner })
}
}

Expand Down
2 changes: 1 addition & 1 deletion der/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ where
fn decode<R: Reader<'a>>(reader: &mut R) -> Result<T, <T as DecodeValue<'a>>::Error> {
let header = Header::decode(reader)?;
header.tag.assert_eq(T::TAG)?;
T::decode_value(reader, header)
reader.read_value(header, |r| T::decode_value(r, header))
}
}

Expand Down
14 changes: 13 additions & 1 deletion der/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ pub trait Reader<'r>: Sized {
E: From<Error>,
F: FnOnce(&mut Self) -> Result<T, E>;

/// Read a value (i.e. the "V" part of a "TLV" field) using the provided header.
///
/// This calls the provided function `f` with a nested reader created using
/// [`Reader::read_nested`].
fn read_value<T, F, E>(&mut self, header: Header, f: F) -> Result<T, E>
where
E: From<Error>,
F: FnOnce(&mut Self) -> Result<T, E>,
{
self.read_nested(header.length, f)
}

/// Attempt to read data borrowed directly from the input as a slice,
/// updating the internal cursor position.
///
Expand Down Expand Up @@ -163,7 +175,7 @@ pub trait Reader<'r>: Sized {
{
let header = Header::decode(self)?;
header.tag.assert_eq(Tag::Sequence)?;
self.read_nested(header.length, f)
self.read_value(header, f)
}

/// Obtain a slice of bytes contain a complete TLV production suitable for parsing later.
Expand Down
20 changes: 6 additions & 14 deletions der_derive/src/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,26 +104,19 @@ impl DeriveSequence {
let error = self.error.to_token_stream();

quote! {
impl #impl_generics #ident #ty_generics #where_clause {
#[doc(hidden)]
fn decode_value_inner<R: ::der::Reader<#lifetime>>(reader: &mut R) -> ::core::result::Result<Self, #error> {
use ::der::{Decode as _, DecodeValue as _, Reader as _};
#(#decode_body)*

Ok(Self {
#(#decode_result),*
})
}
}

impl #impl_generics ::der::DecodeValue<#lifetime> for #ident #ty_generics #where_clause {
type Error = #error;

fn decode_value<R: ::der::Reader<#lifetime>>(
reader: &mut R,
header: ::der::Header,
) -> ::core::result::Result<Self, #error> {
reader.read_nested(header.length, Self::decode_value_inner)
use ::der::{Decode as _, DecodeValue as _, Reader as _};
#(#decode_body)*

Ok(Self {
#(#decode_result),*
})
}
}
}
Expand All @@ -146,7 +139,6 @@ impl DeriveSequence {
}

quote! {

impl #impl_generics ::der::EncodeValue for #ident #ty_generics #where_clause {
fn value_len(&self) -> ::der::Result<::der::Length> {
use ::der::Encode as _;
Expand Down
55 changes: 26 additions & 29 deletions pkcs1/src/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,22 +182,20 @@ impl Default for RsaPssParams<'_> {
impl<'a> DecodeValue<'a> for RsaPssParams<'a> {
type Error = der::Error;

fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
hash: reader
.context_specific(TagNumber(0), TagMode::Explicit)?
.unwrap_or(SHA_1_AI),
mask_gen: reader
.context_specific(TagNumber(1), TagMode::Explicit)?
.unwrap_or_else(default_mgf1_sha1),
salt_len: reader
.context_specific(TagNumber(2), TagMode::Explicit)?
.unwrap_or(RsaPssParams::SALT_LEN_DEFAULT),
trailer_field: reader
.context_specific(TagNumber(3), TagMode::Explicit)?
.unwrap_or_default(),
})
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: der::Header) -> der::Result<Self> {
Ok(Self {
hash: reader
.context_specific(TagNumber(0), TagMode::Explicit)?
.unwrap_or(SHA_1_AI),
mask_gen: reader
.context_specific(TagNumber(1), TagMode::Explicit)?
.unwrap_or_else(default_mgf1_sha1),
salt_len: reader
.context_specific(TagNumber(2), TagMode::Explicit)?
.unwrap_or(RsaPssParams::SALT_LEN_DEFAULT),
trailer_field: reader
.context_specific(TagNumber(3), TagMode::Explicit)?
.unwrap_or_default(),
})
}
}
Expand Down Expand Up @@ -347,19 +345,18 @@ impl Default for RsaOaepParams<'_> {

impl<'a> DecodeValue<'a> for RsaOaepParams<'a> {
type Error = der::Error;
fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
hash: reader
.context_specific(TagNumber(0), TagMode::Explicit)?
.unwrap_or(SHA_1_AI),
mask_gen: reader
.context_specific(TagNumber(1), TagMode::Explicit)?
.unwrap_or_else(default_mgf1_sha1),
p_source: reader
.context_specific(TagNumber(2), TagMode::Explicit)?
.unwrap_or_else(default_pempty_string),
})

fn decode_value<R: Reader<'a>>(reader: &mut R, _header: der::Header) -> der::Result<Self> {
Ok(Self {
hash: reader
.context_specific(TagNumber(0), TagMode::Explicit)?
.unwrap_or(SHA_1_AI),
mask_gen: reader
.context_specific(TagNumber(1), TagMode::Explicit)?
.unwrap_or_else(default_mgf1_sha1),
p_source: reader
.context_specific(TagNumber(2), TagMode::Explicit)?
.unwrap_or_else(default_pempty_string),
})
}
}
Expand Down
44 changes: 21 additions & 23 deletions pkcs1/src/private_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,29 +95,27 @@ impl<'a> RsaPrivateKey<'a> {
impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> {
type Error = der::Error;

fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
let version = Version::decode(reader)?;

let result = Self {
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(reader.error(der::ErrorKind::Value { tag: Tag::Integer }));
}

Ok(result)
})
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
let version = Version::decode(reader)?;

let result = Self {
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(reader.error(der::ErrorKind::Value { tag: Tag::Integer }));
}

Ok(result)
}
}

Expand Down
12 changes: 5 additions & 7 deletions pkcs1/src/private_key/other_prime_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,11 @@ pub struct OtherPrimeInfo<'a> {
impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> {
type Error = der::Error;

fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
prime: reader.decode()?,
exponent: reader.decode()?,
coefficient: reader.decode()?,
})
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
Ok(Self {
prime: reader.decode()?,
exponent: reader.decode()?,
coefficient: reader.decode()?,
})
}
}
Expand Down
Loading