From 3320ff118f296cc2a85228b7f37ca25647bb6725 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Tue, 28 Oct 2025 11:54:28 +0100 Subject: [PATCH 1/2] der: docs: rename variable encoder -> writer --- der/src/asn1/general_string.rs | 4 +-- der/src/asn1/generalized_time.rs | 12 ++++----- der/src/asn1/integer/int.rs | 12 ++++----- der/src/asn1/integer/uint.rs | 12 ++++----- der/src/asn1/optional.rs | 4 +-- der/src/asn1/utc_time.rs | 6 ++--- der/src/error.rs | 5 +++- der/src/lib.rs | 32 ++++++++---------------- der/src/writer/slice.rs | 8 +++--- der/tests/datetime.rs | 6 ++--- der/tests/derive.rs | 42 ++++++++++++++++---------------- 11 files changed, 67 insertions(+), 76 deletions(-) diff --git a/der/src/asn1/general_string.rs b/der/src/asn1/general_string.rs index 97bc963ea..c1133f2d1 100644 --- a/der/src/asn1/general_string.rs +++ b/der/src/asn1/general_string.rs @@ -30,7 +30,7 @@ impl EncodeValue for GeneralStringRef<'_> { self.inner.value_len() } - fn encode_value(&self, encoder: &mut impl Writer) -> crate::Result<()> { - self.inner.encode_value(encoder) + fn encode_value(&self, writer: &mut impl Writer) -> crate::Result<()> { + self.inner.encode_value(writer) } } diff --git a/der/src/asn1/generalized_time.rs b/der/src/asn1/generalized_time.rs index c000c95f4..a1d9fa1a9 100644 --- a/der/src/asn1/generalized_time.rs +++ b/der/src/asn1/generalized_time.rs @@ -343,9 +343,9 @@ mod tests { assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - utc_time.encode(&mut encoder).unwrap(); - assert_eq!(example_bytes, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + utc_time.encode(&mut writer).unwrap(); + assert_eq!(example_bytes, writer.finish().unwrap()); } #[test] @@ -355,9 +355,9 @@ mod tests { assert_eq!(utc_time.to_unix_duration().as_secs(), 253402300799); let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - utc_time.encode(&mut encoder).unwrap(); - assert_eq!(example_bytes, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + utc_time.encode(&mut writer).unwrap(); + assert_eq!(example_bytes, writer.finish().unwrap()); } #[test] diff --git a/der/src/asn1/integer/int.rs b/der/src/asn1/integer/int.rs index b6541f55a..2dec0559a 100644 --- a/der/src/asn1/integer/int.rs +++ b/der/src/asn1/integer/int.rs @@ -507,10 +507,10 @@ mod tests { let uint = IntRef::from_der(example).unwrap(); let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - uint.encode(&mut encoder).unwrap(); + let mut writer = SliceWriter::new(&mut buf); + uint.encode(&mut writer).unwrap(); - let result = encoder.finish().unwrap(); + let result = writer.finish().unwrap(); assert_eq!(example, result); } @@ -518,10 +518,10 @@ mod tests { let uint = IntRef::from_der(example).unwrap(); let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - uint.encode(&mut encoder).unwrap(); + let mut writer = SliceWriter::new(&mut buf); + uint.encode(&mut writer).unwrap(); - let result = encoder.finish().unwrap(); + let result = writer.finish().unwrap(); assert_eq!(example, result); } } diff --git a/der/src/asn1/integer/uint.rs b/der/src/asn1/integer/uint.rs index 9c0024078..fedb162d2 100644 --- a/der/src/asn1/integer/uint.rs +++ b/der/src/asn1/integer/uint.rs @@ -353,17 +353,17 @@ pub(super) fn decode_to_array(bytes: &[u8]) -> Result<[u8; N]> { } /// Encode the given big endian bytes representing an integer as ASN.1 DER. -pub(crate) fn encode_bytes(encoder: &mut W, bytes: &[u8]) -> Result<()> +pub(crate) fn encode_bytes(writer: &mut W, bytes: &[u8]) -> Result<()> where W: Writer + ?Sized, { let bytes = strip_leading_zeroes(bytes); if needs_leading_zero(bytes) { - encoder.write_byte(0)?; + writer.write_byte(0)?; } - encoder.write(bytes) + writer.write(bytes) } /// Get the encoded length for the given unsigned integer serialized as bytes. @@ -459,10 +459,10 @@ mod tests { let uint = UintRef::from_der(example).unwrap(); let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - uint.encode(&mut encoder).unwrap(); + let mut writer = SliceWriter::new(&mut buf); + uint.encode(&mut writer).unwrap(); - let result = encoder.finish().unwrap(); + let result = writer.finish().unwrap(); assert_eq!(example, result); } } diff --git a/der/src/asn1/optional.rs b/der/src/asn1/optional.rs index b0063fbcb..dd0775720 100644 --- a/der/src/asn1/optional.rs +++ b/der/src/asn1/optional.rs @@ -61,9 +61,9 @@ where } } - fn encode(&self, encoder: &mut impl Writer) -> Result<(), Error> { + fn encode(&self, writer: &mut impl Writer) -> Result<(), Error> { match self { - Some(encodable) => encodable.encode(encoder), + Some(encodable) => encodable.encode(writer), None => Ok(()), } } diff --git a/der/src/asn1/utc_time.rs b/der/src/asn1/utc_time.rs index 6a4895680..32b0e3c16 100644 --- a/der/src/asn1/utc_time.rs +++ b/der/src/asn1/utc_time.rs @@ -252,8 +252,8 @@ mod tests { assert_eq!(utc_time.to_unix_duration().as_secs(), 673573540); let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - utc_time.encode(&mut encoder).unwrap(); - assert_eq!(example_bytes, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + utc_time.encode(&mut writer).unwrap(); + assert_eq!(example_bytes, writer.finish().unwrap()); } } diff --git a/der/src/error.rs b/der/src/error.rs index 215daf159..6fbd12685 100644 --- a/der/src/error.rs +++ b/der/src/error.rs @@ -11,6 +11,9 @@ use crate::asn1::ObjectIdentifier; #[cfg(feature = "pem")] use crate::pem; +#[cfg(doc)] +use crate::{Reader, Writer}; + /// Result type. pub type Result = core::result::Result; @@ -196,7 +199,7 @@ pub enum ErrorKind { EncodingRules, /// This error indicates a previous DER parsing operation resulted in - /// an error and tainted the state of a `Decoder` or `Encoder`. + /// an error and tainted the state of a [`Reader`] or [`Writer`]. /// /// Once this occurs, the overall operation has failed and cannot be /// subsequently resumed. diff --git a/der/src/lib.rs b/der/src/lib.rs index cbab369dd..2980b9207 100644 --- a/der/src/lib.rs +++ b/der/src/lib.rs @@ -113,30 +113,18 @@ //! type Error = der::Error; //! //! fn decode_value>(reader: &mut R, _header: Header) -> der::Result { -//! // The `der::Decoder::Decode` method can be used to decode any +//! // The `der::Decode::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. +//! // The value returned from this `decode_value` will be +//! // returned from the `AlgorithmIdentifier::decode` call, unchanged. //! // Note that the entire sequence body *MUST* be consumed //! // or an error will be returned. //! Ok(Self { algorithm, parameters }) @@ -171,15 +159,15 @@ //! // which impls `Sequence` can be serialized by calling `Encode::to_der()`. //! // //! // If you would prefer to avoid allocations, you can create a byte array -//! // as backing storage instead, pass that to `der::Encoder::new`, and then -//! // encode the `parameters` value using `encoder.encode(parameters)`. +//! // as backing storage instead, pass that to `der::SliceWriter::new`, and then +//! // encode the `parameters` value using `writer.encode(parameters)`. //! let der_encoded_parameters = parameters.to_der().unwrap(); //! //! let algorithm_identifier = AlgorithmIdentifier { //! // OID for `id-ecPublicKey`, if you're curious //! algorithm: "1.2.840.10045.2.1".parse().unwrap(), //! -//! // `Any<'a>` impls `TryFrom<&'a [u8]>`, which parses the provided +//! // `AnyRef<'a>` impls `TryFrom<&'a [u8]>`, which parses the provided //! // slice as an ASN.1 DER-encoded message. //! parameters: Some(der_encoded_parameters.as_slice().try_into().unwrap()) //! }; @@ -188,14 +176,14 @@ //! // allocating a `Vec` for storage. //! // //! // As mentioned earlier, if you don't have the `alloc` feature enabled you -//! // can create a fix-sized array instead, then call `Encoder::new` with a +//! // can create a fix-sized array instead, then call `SliceWriter::new` with a //! // reference to it, then encode the message using -//! // `encoder.encode(algorithm_identifier)`, then finally `encoder.finish()` +//! // `writer.encode(algorithm_identifier)`, then finally `writer.finish()` //! // to obtain a byte slice containing the encoded message. //! let der_encoded_algorithm_identifier = algorithm_identifier.to_der().unwrap(); //! -//! // Deserialize the `AlgorithmIdentifier` we just serialized from ASN.1 DER -//! // using `der::Decode::from_bytes`. +//! // Deserialize the `AlgorithmIdentifier` bytes we just serialized from ASN.1 DER +//! // using `der::Decode::from_der`. //! let decoded_algorithm_identifier = AlgorithmIdentifier::from_der( //! &der_encoded_algorithm_identifier //! ).unwrap(); diff --git a/der/src/writer/slice.rs b/der/src/writer/slice.rs index 9000f32dc..0d527b2f0 100644 --- a/der/src/writer/slice.rs +++ b/der/src/writer/slice.rs @@ -19,7 +19,7 @@ pub struct SliceWriter<'a> { } impl<'a> SliceWriter<'a> { - /// Create a new encoder with the given byte slice as a backing buffer. + /// Create a new writer with the given byte slice as a backing buffer. pub fn new(bytes: &'a mut [u8]) -> Self { Self { bytes, @@ -94,10 +94,10 @@ impl<'a> SliceWriter<'a> { { Header::new(Tag::Sequence, length).encode(self)?; - let mut nested_encoder = SliceWriter::new(self.reserve(length)?); - f(&mut nested_encoder)?; + let mut nested_writer = SliceWriter::new(self.reserve(length)?); + f(&mut nested_writer)?; - if nested_encoder.finish()?.len() == usize::try_from(length)? { + if nested_writer.finish()?.len() == usize::try_from(length)? { Ok(()) } else { self.error(ErrorKind::Length { tag: Tag::Sequence }) diff --git a/der/tests/datetime.rs b/der/tests/datetime.rs index 8883c3bee..4efc1c422 100644 --- a/der/tests/datetime.rs +++ b/der/tests/datetime.rs @@ -31,9 +31,9 @@ proptest! { let utc_time1 = UtcTime::try_from(datetime).unwrap(); let mut buf = [0u8; 128]; - let mut encoder = der::SliceWriter::new(&mut buf); - utc_time1.encode(&mut encoder).unwrap(); - let der_bytes = encoder.finish().unwrap(); + let mut writer = der::SliceWriter::new(&mut buf); + utc_time1.encode(&mut writer).unwrap(); + let der_bytes = writer.finish().unwrap(); let utc_time2 = UtcTime::from_der(der_bytes).unwrap(); prop_assert_eq!(utc_time1, utc_time2); diff --git a/der/tests/derive.rs b/der/tests/derive.rs index b94748b26..ebb71bfe0 100644 --- a/der/tests/derive.rs +++ b/der/tests/derive.rs @@ -98,14 +98,14 @@ mod choice { let mut buf = [0u8; 128]; let utc_time = Time::from_der(UTC_TIMESTAMP_DER).unwrap(); - let mut encoder = SliceWriter::new(&mut buf); - utc_time.encode(&mut encoder).unwrap(); - assert_eq!(UTC_TIMESTAMP_DER, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + utc_time.encode(&mut writer).unwrap(); + assert_eq!(UTC_TIMESTAMP_DER, writer.finish().unwrap()); let general_time = Time::from_der(GENERAL_TIMESTAMP_DER).unwrap(); - let mut encoder = SliceWriter::new(&mut buf); - general_time.encode(&mut encoder).unwrap(); - assert_eq!(GENERAL_TIMESTAMP_DER, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + general_time.encode(&mut writer).unwrap(); + assert_eq!(GENERAL_TIMESTAMP_DER, writer.finish().unwrap()); } } @@ -174,14 +174,14 @@ mod choice { let mut buf = [0u8; 128]; let cs_bit_string = ImplicitChoice::from_der(BITSTRING_DER).unwrap(); - let mut encoder = SliceWriter::new(&mut buf); - cs_bit_string.encode(&mut encoder).unwrap(); - assert_eq!(BITSTRING_DER, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + cs_bit_string.encode(&mut writer).unwrap(); + assert_eq!(BITSTRING_DER, writer.finish().unwrap()); let cs_time = ImplicitChoice::from_der(TIME_DER).unwrap(); - let mut encoder = SliceWriter::new(&mut buf); - cs_time.encode(&mut encoder).unwrap(); - assert_eq!(TIME_DER, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + cs_time.encode(&mut writer).unwrap(); + assert_eq!(TIME_DER, writer.finish().unwrap()); } #[test] @@ -191,10 +191,10 @@ mod choice { let obj = ImplicitChoice::SequenceOfNulls(seq); let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - obj.encode(&mut encoder).unwrap(); + let mut writer = SliceWriter::new(&mut buf); + obj.encode(&mut writer).unwrap(); - let encoded = encoder.finish().unwrap(); + let encoded = writer.finish().unwrap(); println!("encoded: {encoded:02X?}"); let decoded = ImplicitChoice::from_der(encoded).unwrap(); @@ -261,13 +261,13 @@ mod enumerated { fn encode() { let mut buf = [0u8; 128]; - let mut encoder = SliceWriter::new(&mut buf); - CrlReason::Unspecified.encode(&mut encoder).unwrap(); - assert_eq!(UNSPECIFIED_DER, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + CrlReason::Unspecified.encode(&mut writer).unwrap(); + assert_eq!(UNSPECIFIED_DER, writer.finish().unwrap()); - let mut encoder = SliceWriter::new(&mut buf); - CrlReason::KeyCompromise.encode(&mut encoder).unwrap(); - assert_eq!(KEY_COMPROMISE_DER, encoder.finish().unwrap()); + let mut writer = SliceWriter::new(&mut buf); + CrlReason::KeyCompromise.encode(&mut writer).unwrap(); + assert_eq!(KEY_COMPROMISE_DER, writer.finish().unwrap()); } } From ee9e612d7d3341bc44ff29f21417287abbbfb282 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:50:55 +0100 Subject: [PATCH 2/2] der: document example impl EncodeValue for AlgorithmIdentifier<'a> --- der/src/lib.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/der/src/lib.rs b/der/src/lib.rs index 2980b9207..9a1ed38d9 100644 --- a/der/src/lib.rs +++ b/der/src/lib.rs @@ -95,7 +95,8 @@ //! // "heapless" usage when the `alloc` feature is disabled. //! use der::{ //! asn1::{AnyRef, ObjectIdentifier}, -//! DecodeValue, Decode, SliceReader, Encode, Header, Reader, Sequence +//! Decode, DecodeValue, Encode, EncodeValue, Header, Length, +//! Reader, Sequence, SliceReader, Writer //! }; //! //! /// X.509 `AlgorithmIdentifier`. @@ -131,12 +132,16 @@ //! } //! } //! -//! impl<'a> ::der::EncodeValue for AlgorithmIdentifier<'a> { -//! fn value_len(&self) -> ::der::Result<::der::Length> { +//! impl<'a> EncodeValue for AlgorithmIdentifier<'a> { +//! fn value_len(&self) -> der::Result { +//! // Length of the Value part in Tag-Length-Value structure +//! // is calculated for every TLV header in the tree. +//! // Therefore, in this example `AlgorithmIdentifier::value_len` +//! // will be called once, originating from `Encode::to_der()`. //! self.algorithm.encoded_len()? + self.parameters.encoded_len()? //! } //! -//! fn encode_value(&self, writer: &mut impl ::der::Writer) -> ::der::Result<()> { +//! fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { //! self.algorithm.encode(writer)?; //! self.parameters.encode(writer)?; //! Ok(())