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