der/
encode.rs

1//! Trait definition for [`Encode`].
2
3use crate::{Header, Length, Result, SliceWriter, Tagged, Writer};
4use core::marker::PhantomData;
5
6#[cfg(feature = "alloc")]
7use {alloc::boxed::Box, alloc::vec::Vec, core::iter};
8
9#[cfg(feature = "pem")]
10use {
11    crate::PemWriter,
12    alloc::string::String,
13    pem_rfc7468::{self as pem, LineEnding, PemLabel},
14};
15
16#[cfg(any(feature = "alloc", feature = "pem"))]
17use crate::ErrorKind;
18
19#[cfg(doc)]
20use crate::Tag;
21
22/// Encoding trait.
23pub trait Encode {
24    /// Compute the length of this value in bytes when encoded as ASN.1 DER.
25    fn encoded_len(&self) -> Result<Length>;
26
27    /// Encode this value as ASN.1 DER using the provided [`Writer`].
28    fn encode(&self, encoder: &mut impl Writer) -> Result<()>;
29
30    /// Encode this value to the provided byte slice, returning a sub-slice
31    /// containing the encoded message.
32    fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
33        let mut writer = SliceWriter::new(buf);
34        self.encode(&mut writer)?;
35        writer.finish()
36    }
37
38    /// Encode this message as ASN.1 DER, appending it to the provided
39    /// byte vector.
40    #[cfg(feature = "alloc")]
41    fn encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length> {
42        let expected_len = usize::try_from(self.encoded_len()?)?;
43        buf.reserve(expected_len);
44        buf.extend(iter::repeat(0).take(expected_len));
45
46        let mut writer = SliceWriter::new(buf);
47        self.encode(&mut writer)?;
48        let actual_len = writer.finish()?.len();
49
50        if expected_len != actual_len {
51            return Err(ErrorKind::Incomplete {
52                expected_len: expected_len.try_into()?,
53                actual_len: actual_len.try_into()?,
54            }
55            .into());
56        }
57
58        actual_len.try_into()
59    }
60
61    /// Encode this type as DER, returning a byte vector.
62    #[cfg(feature = "alloc")]
63    fn to_der(&self) -> Result<Vec<u8>> {
64        let mut buf = Vec::new();
65        self.encode_to_vec(&mut buf)?;
66        Ok(buf)
67    }
68}
69
70impl<T> Encode for T
71where
72    T: EncodeValue + Tagged,
73{
74    /// Compute the length of this value in bytes when encoded as ASN.1 DER.
75    fn encoded_len(&self) -> Result<Length> {
76        self.value_len().and_then(|len| len.for_tlv())
77    }
78
79    /// Encode this value as ASN.1 DER using the provided [`Writer`].
80    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
81        self.header()?.encode(writer)?;
82        self.encode_value(writer)
83    }
84}
85
86/// Dummy implementation for [`PhantomData`] which allows deriving
87/// implementations on structs with phantom fields.
88impl<T> Encode for PhantomData<T>
89where
90    T: ?Sized,
91{
92    fn encoded_len(&self) -> Result<Length> {
93        Ok(Length::ZERO)
94    }
95
96    fn encode(&self, _writer: &mut impl Writer) -> Result<()> {
97        Ok(())
98    }
99}
100
101/// PEM encoding trait.
102///
103/// This trait is automatically impl'd for any type which impls both
104/// [`Encode`] and [`PemLabel`].
105#[cfg(feature = "pem")]
106pub trait EncodePem: Encode + PemLabel {
107    /// Try to encode this type as PEM.
108    fn to_pem(&self, line_ending: LineEnding) -> Result<String>;
109}
110
111#[cfg(feature = "pem")]
112impl<T: Encode + PemLabel> EncodePem for T {
113    fn to_pem(&self, line_ending: LineEnding) -> Result<String> {
114        let der_len = usize::try_from(self.encoded_len()?)?;
115        let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?;
116
117        let mut buf = vec![0u8; pem_len];
118        let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?;
119        self.encode(&mut writer)?;
120
121        let actual_len = writer.finish()?;
122        buf.truncate(actual_len);
123        Ok(String::from_utf8(buf)?)
124    }
125}
126
127/// Encode the value part of a Tag-Length-Value encoded field, sans the [`Tag`]
128/// and [`Length`].
129pub trait EncodeValue {
130    /// Get the [`Header`] used to encode this value.
131    fn header(&self) -> Result<Header>
132    where
133        Self: Tagged,
134    {
135        Header::new(self.tag(), self.value_len()?)
136    }
137
138    /// Compute the length of this value (sans [`Tag`]+[`Length`] header) when
139    /// encoded as ASN.1 DER.
140    fn value_len(&self) -> Result<Length>;
141
142    /// Encode value (sans [`Tag`]+[`Length`] header) as ASN.1 DER using the
143    /// provided [`Writer`].
144    fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>;
145}
146
147#[cfg(feature = "alloc")]
148impl<T> EncodeValue for Box<T>
149where
150    T: EncodeValue,
151{
152    fn value_len(&self) -> Result<Length> {
153        T::value_len(self)
154    }
155    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
156        T::encode_value(self, writer)
157    }
158}