1 //! Trait definition for [`Encode`].
2 
3 use crate::{Header, Length, Result, SliceWriter, Tagged, Writer};
4 use core::marker::PhantomData;
5 
6 #[cfg(feature = "alloc")]
7 use {alloc::boxed::Box, alloc::vec::Vec, core::iter};
8 
9 #[cfg(feature = "pem")]
10 use {
11     crate::PemWriter,
12     alloc::string::String,
13     pem_rfc7468::{self as pem, LineEnding, PemLabel},
14 };
15 
16 #[cfg(any(feature = "alloc", feature = "pem"))]
17 use crate::ErrorKind;
18 
19 #[cfg(doc)]
20 use crate::Tag;
21 
22 /// Encoding trait.
23 pub trait Encode {
24     /// Compute the length of this value in bytes when encoded as ASN.1 DER.
encoded_len(&self) -> Result<Length>25     fn encoded_len(&self) -> Result<Length>;
26 
27     /// Encode this value as ASN.1 DER using the provided [`Writer`].
encode(&self, encoder: &mut impl Writer) -> Result<()>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.
encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]>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")]
encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length>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")]
to_der(&self) -> Result<Vec<u8>>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 
70 impl<T> Encode for T
71 where
72     T: EncodeValue + Tagged,
73 {
74     /// Compute the length of this value in bytes when encoded as ASN.1 DER.
encoded_len(&self) -> Result<Length>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`].
encode(&self, writer: &mut impl Writer) -> Result<()>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.
88 impl<T> Encode for PhantomData<T>
89 where
90     T: ?Sized,
91 {
encoded_len(&self) -> Result<Length>92     fn encoded_len(&self) -> Result<Length> {
93         Ok(Length::ZERO)
94     }
95 
encode(&self, _writer: &mut impl Writer) -> Result<()>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")]
106 pub trait EncodePem: Encode + PemLabel {
107     /// Try to encode this type as PEM.
to_pem(&self, line_ending: LineEnding) -> Result<String>108     fn to_pem(&self, line_ending: LineEnding) -> Result<String>;
109 }
110 
111 #[cfg(feature = "pem")]
112 impl<T: Encode + PemLabel> EncodePem for T {
to_pem(&self, line_ending: LineEnding) -> Result<String>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`].
129 pub trait EncodeValue {
130     /// Get the [`Header`] used to encode this value.
header(&self) -> Result<Header> where Self: Tagged,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.
value_len(&self) -> Result<Length>140     fn value_len(&self) -> Result<Length>;
141 
142     /// Encode value (sans [`Tag`]+[`Length`] header) as ASN.1 DER using the
143     /// provided [`Writer`].
encode_value(&self, encoder: &mut impl Writer) -> Result<()>144     fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>;
145 }
146 
147 #[cfg(feature = "alloc")]
148 impl<T> EncodeValue for Box<T>
149 where
150     T: EncodeValue,
151 {
value_len(&self) -> Result<Length>152     fn value_len(&self) -> Result<Length> {
153         T::value_len(self)
154     }
encode_value(&self, writer: &mut impl Writer) -> Result<()>155     fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
156         T::encode_value(self, writer)
157     }
158 }
159