Skip to main content

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::{
8    borrow::{Cow, ToOwned},
9    boxed::Box,
10    vec::Vec,
11};
12
13#[cfg(feature = "pem")]
14use {
15    crate::PemWriter,
16    alloc::string::String,
17    pem_rfc7468::{self as pem, LineEnding, PemLabel},
18};
19
20#[cfg(any(feature = "alloc", feature = "pem"))]
21use crate::ErrorKind;
22
23#[cfg(doc)]
24use crate::{FixedTag, Tag};
25
26/// Encode trait produces a complete TLV (Tag-Length-Value) structure.
27///
28/// As opposed to [`EncodeValue`], implementer is expected to write whole ASN.1 DER header, before writing value.
29///
30/// ## Example
31///
32/// ```
33/// # #[cfg(all(feature = "alloc", feature = "std"))]
34/// # {
35/// use der::{Any, Encode, Length, Reader, Writer};
36///
37/// /// Wrapper around Any, with custom foreign trait support.
38/// ///
39/// /// For example: serde Serialize/Deserialize
40/// pub struct AnySerde(pub Any);
41///
42/// impl Encode for AnySerde {
43///
44///     fn encoded_len(&self) -> der::Result<Length> {
45///         self.0.encoded_len()
46///     }
47///
48///     fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
49///         self.0.encode(writer)
50///     }
51/// }
52/// # }
53/// ```
54#[diagnostic::on_unimplemented(
55    note = "Consider adding impls of `EncodeValue` and `FixedTag` to `{Self}`"
56)]
57pub trait Encode {
58    /// Compute the length of this TLV object in bytes when encoded as ASN.1 DER.
59    ///
60    /// # Errors
61    /// Returns an error if the length could not be computed (e.g. overflow).
62    fn encoded_len(&self) -> Result<Length>;
63
64    /// Encode this TLV object as ASN.1 DER using the provided [`Writer`].
65    ///
66    /// # Errors
67    /// In the event an encoding error occurred.
68    fn encode(&self, writer: &mut impl Writer) -> Result<()>;
69
70    /// Encode this TLV object to the provided byte slice, returning a sub-slice
71    /// containing the encoded message.
72    ///
73    /// # Errors
74    /// In the event an encoding error occurred.
75    fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
76        let mut writer = SliceWriter::new(buf);
77        self.encode(&mut writer)?;
78        writer.finish()
79    }
80
81    /// Encode this TLV object as ASN.1 DER, appending it to the provided
82    /// byte vector.
83    ///
84    /// # Errors
85    /// In the event an encoding error occurred.
86    #[cfg(feature = "alloc")]
87    fn encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length> {
88        let expected_len = usize::try_from(self.encoded_len()?)?;
89        let initial_len = buf.len();
90        buf.resize(initial_len + expected_len, 0u8);
91
92        let buf_slice = &mut buf[initial_len..];
93        let actual_len = self.encode_to_slice(buf_slice)?.len();
94
95        if expected_len != actual_len {
96            return Err(ErrorKind::Incomplete {
97                expected_len: expected_len.try_into()?,
98                actual_len: actual_len.try_into()?,
99            }
100            .into());
101        }
102
103        actual_len.try_into()
104    }
105
106    /// Encode this TLV object as ASN.1 DER, returning a byte vector.
107    ///
108    /// # Errors
109    /// In the event an encoding error occurred.
110    #[cfg(feature = "alloc")]
111    fn to_der(&self) -> Result<Vec<u8>> {
112        let mut buf = Vec::new();
113        self.encode_to_vec(&mut buf)?;
114        Ok(buf)
115    }
116}
117
118impl<T> Encode for T
119where
120    T: EncodeValue + Tagged + ?Sized,
121{
122    fn encoded_len(&self) -> Result<Length> {
123        self.value_len().and_then(|len| len.for_tlv(self.tag()))
124    }
125
126    fn encode(&self, writer: &mut impl Writer) -> Result<()> {
127        self.header()?.encode(writer)?;
128        self.encode_value(writer)
129    }
130}
131
132/// Dummy implementation for [`PhantomData`] which allows deriving
133/// implementations on structs with phantom fields.
134impl<T> Encode for PhantomData<T>
135where
136    T: ?Sized,
137{
138    fn encoded_len(&self) -> Result<Length> {
139        Ok(Length::ZERO)
140    }
141
142    fn encode(&self, _writer: &mut impl Writer) -> Result<()> {
143        Ok(())
144    }
145}
146
147/// PEM encoding trait.
148///
149/// This trait is automatically impl'd for any type which impls both
150/// [`Encode`] and [`PemLabel`].
151#[cfg(feature = "pem")]
152#[diagnostic::on_unimplemented(
153    note = "`EncodePem` is auto-impl'd for types which impl both `Encode` and `PemLabel`"
154)]
155pub trait EncodePem: Encode + PemLabel {
156    /// Try to encode this type as PEM.
157    ///
158    /// # Errors
159    /// If a PEM encoding error occurred.
160    fn to_pem(&self, line_ending: LineEnding) -> Result<String>;
161}
162
163#[cfg(feature = "pem")]
164impl<T> EncodePem for T
165where
166    T: Encode + PemLabel + ?Sized,
167{
168    fn to_pem(&self, line_ending: LineEnding) -> Result<String> {
169        let der_len = usize::try_from(self.encoded_len()?)?;
170        let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?;
171
172        let mut buf = vec![0u8; pem_len];
173        let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?;
174        self.encode(&mut writer)?;
175
176        let actual_len = writer.finish()?;
177        buf.truncate(actual_len);
178        Ok(String::from_utf8(buf)?)
179    }
180}
181
182/// Encode the value part of a Tag-Length-Value encoded field, sans the [`Tag`]
183/// and [`Length`].
184///
185/// As opposed to [`Encode`], implementer is expected to write the inner content only,
186/// without the [`Header`].
187///
188/// When [`EncodeValue`] is paired with [`FixedTag`],
189/// it produces a complete TLV ASN.1 DER encoding as [`Encode`] trait.
190///
191/// ## Example
192/// ```
193/// use der::{Encode, EncodeValue, ErrorKind, FixedTag, Length, Tag, Writer};
194///
195/// /// 1-byte month
196/// struct MyByteMonth(u8);
197///
198/// impl EncodeValue for MyByteMonth {
199///
200///     fn value_len(&self) -> der::Result<Length> {
201///         Ok(Length::new(1))
202///     }
203///
204///     fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
205///         writer.write_byte(self.0)?;
206///         Ok(())
207///     }
208/// }
209///
210/// impl FixedTag for MyByteMonth {
211///     const TAG: Tag = Tag::OctetString;
212/// }
213///
214/// let month = MyByteMonth(9);
215/// let mut buf = [0u8; 16];
216/// let month_der = month.encode_to_slice(&mut buf).expect("month to encode");
217///
218/// assert_eq!(month_der, b"\x04\x01\x09");
219/// ```
220pub trait EncodeValue {
221    /// Get the [`Header`] used to encode this value.
222    ///
223    /// # Errors
224    /// Returns an error if the header could not be computed.
225    fn header(&self) -> Result<Header>
226    where
227        Self: Tagged,
228    {
229        Ok(Header::new(self.tag(), self.value_len()?))
230    }
231
232    /// Compute the length of this value (sans [`Tag`]+[`Length`] header) when
233    /// encoded as ASN.1 DER.
234    ///
235    /// # Errors
236    /// Returns an error if the value length could not be computed (e.g. overflow).
237    fn value_len(&self) -> Result<Length>;
238
239    /// Encode value (sans [`Tag`]+[`Length`] header) as ASN.1 DER using the
240    /// provided [`Writer`].
241    ///
242    /// # Errors
243    /// In the event an encoding error occurred.
244    fn encode_value(&self, writer: &mut impl Writer) -> Result<()>;
245}
246
247#[cfg(feature = "alloc")]
248impl<T> EncodeValue for Box<T>
249where
250    T: EncodeValue,
251{
252    fn value_len(&self) -> Result<Length> {
253        T::value_len(self)
254    }
255    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
256        T::encode_value(self, writer)
257    }
258}
259
260#[cfg(feature = "alloc")]
261impl<T> EncodeValue for Cow<'_, T>
262where
263    T: ToOwned + ?Sized,
264    for<'a> &'a T: EncodeValue,
265{
266    fn value_len(&self) -> Result<Length> {
267        self.as_ref().value_len()
268    }
269
270    fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
271        self.as_ref().encode_value(writer)
272    }
273}
274
275/// Encodes value only (without tag + length) to a slice.
276pub(crate) fn encode_value_to_slice<'a, T>(buf: &'a mut [u8], value: &T) -> Result<&'a [u8]>
277where
278    T: EncodeValue,
279{
280    let mut writer = SliceWriter::new(buf);
281    value.encode_value(&mut writer)?;
282    writer.finish()
283}