Skip to content

Conversation

@dishmaker
Copy link
Contributor

@dishmaker dishmaker commented Oct 28, 2025

Also, I changed the docs in der/src/lib.rs, so it is now:

// Note: the following example does not require the `std` feature at all.
// It does leverage the `alloc` feature, but also provides instructions for
// "heapless" usage when the `alloc` feature is disabled.
use der::{
    asn1::{AnyRef, ObjectIdentifier},
    Decode, DecodeValue, Encode, EncodeValue, Header, Length,
    Reader, Sequence, SliceReader, Writer
};

/// X.509 `AlgorithmIdentifier`.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct AlgorithmIdentifier<'a> {
    /// This field contains an ASN.1 `OBJECT IDENTIFIER`, a.k.a. OID.
    pub algorithm: ObjectIdentifier,

    /// This field is `OPTIONAL` and contains the ASN.1 `ANY` type, which
    /// in this example allows arbitrary algorithm-defined parameters.
    pub parameters: Option<AnyRef<'a>>
}

impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> {
    type Error = der::Error;

    fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
       // 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.
       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`.
       let parameters = reader.decode()?;

       // 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 })
    }
}

impl<'a> EncodeValue for AlgorithmIdentifier<'a> {
    fn value_len(&self) -> der::Result<Length> {
        // 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 Writer) -> der::Result<()> {
        self.algorithm.encode(writer)?;
        self.parameters.encode(writer)?;
        Ok(())
    }
}

impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> {}

// Example parameters value: OID for the NIST P-256 elliptic curve.
let parameters = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap();

// We need to convert `parameters` into an `Any<'a>` type, which wraps a
// `&'a [u8]` byte slice.
//
// To do that, we need owned DER-encoded data so that we can have
// `AnyRef` borrow a reference to it, so we have to serialize the OID.
//
// When the `alloc` feature of this crate is enabled, any type that impls
// the `Encode` trait including all ASN.1 built-in types and any type
// 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::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(),

    // `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())
};

// Serialize the `AlgorithmIdentifier` created above as ASN.1 DER,
// allocating a `Vec<u8>` for storage.
//
// As mentioned earlier, if you don't have the `alloc` feature enabled you
// can create a fix-sized array instead, then call `SliceWriter::new` with a
// reference to it, then encode the message using
// `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` 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();

// Ensure the original `AlgorithmIdentifier` is the same as the one we just
// decoded from ASN.1 DER.
assert_eq!(algorithm_identifier, decoded_algorithm_identifier);

@dishmaker dishmaker changed the title der: docs: rename variable encoder -> writer der: docs: rename variable encoder -> writer and improve example Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant