summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/encode.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/der/src/encode.rs')
-rw-r--r--vendor/der/src/encode.rs158
1 files changed, 158 insertions, 0 deletions
diff --git a/vendor/der/src/encode.rs b/vendor/der/src/encode.rs
new file mode 100644
index 0000000..28d7cba
--- /dev/null
+++ b/vendor/der/src/encode.rs
@@ -0,0 +1,158 @@
+//! Trait definition for [`Encode`].
+
+use crate::{Header, Length, Result, SliceWriter, Tagged, Writer};
+use core::marker::PhantomData;
+
+#[cfg(feature = "alloc")]
+use {alloc::boxed::Box, alloc::vec::Vec, core::iter};
+
+#[cfg(feature = "pem")]
+use {
+ crate::PemWriter,
+ alloc::string::String,
+ pem_rfc7468::{self as pem, LineEnding, PemLabel},
+};
+
+#[cfg(any(feature = "alloc", feature = "pem"))]
+use crate::ErrorKind;
+
+#[cfg(doc)]
+use crate::Tag;
+
+/// Encoding trait.
+pub trait Encode {
+ /// Compute the length of this value in bytes when encoded as ASN.1 DER.
+ fn encoded_len(&self) -> Result<Length>;
+
+ /// Encode this value as ASN.1 DER using the provided [`Writer`].
+ fn encode(&self, encoder: &mut impl Writer) -> Result<()>;
+
+ /// Encode this value to the provided byte slice, returning a sub-slice
+ /// containing the encoded message.
+ fn encode_to_slice<'a>(&self, buf: &'a mut [u8]) -> Result<&'a [u8]> {
+ let mut writer = SliceWriter::new(buf);
+ self.encode(&mut writer)?;
+ writer.finish()
+ }
+
+ /// Encode this message as ASN.1 DER, appending it to the provided
+ /// byte vector.
+ #[cfg(feature = "alloc")]
+ fn encode_to_vec(&self, buf: &mut Vec<u8>) -> Result<Length> {
+ let expected_len = usize::try_from(self.encoded_len()?)?;
+ buf.reserve(expected_len);
+ buf.extend(iter::repeat(0).take(expected_len));
+
+ let mut writer = SliceWriter::new(buf);
+ self.encode(&mut writer)?;
+ let actual_len = writer.finish()?.len();
+
+ if expected_len != actual_len {
+ return Err(ErrorKind::Incomplete {
+ expected_len: expected_len.try_into()?,
+ actual_len: actual_len.try_into()?,
+ }
+ .into());
+ }
+
+ actual_len.try_into()
+ }
+
+ /// Encode this type as DER, returning a byte vector.
+ #[cfg(feature = "alloc")]
+ fn to_der(&self) -> Result<Vec<u8>> {
+ let mut buf = Vec::new();
+ self.encode_to_vec(&mut buf)?;
+ Ok(buf)
+ }
+}
+
+impl<T> Encode for T
+where
+ T: EncodeValue + Tagged,
+{
+ /// Compute the length of this value in bytes when encoded as ASN.1 DER.
+ fn encoded_len(&self) -> Result<Length> {
+ self.value_len().and_then(|len| len.for_tlv())
+ }
+
+ /// Encode this value as ASN.1 DER using the provided [`Writer`].
+ fn encode(&self, writer: &mut impl Writer) -> Result<()> {
+ self.header()?.encode(writer)?;
+ self.encode_value(writer)
+ }
+}
+
+/// Dummy implementation for [`PhantomData`] which allows deriving
+/// implementations on structs with phantom fields.
+impl<T> Encode for PhantomData<T>
+where
+ T: ?Sized,
+{
+ fn encoded_len(&self) -> Result<Length> {
+ Ok(Length::ZERO)
+ }
+
+ fn encode(&self, _writer: &mut impl Writer) -> Result<()> {
+ Ok(())
+ }
+}
+
+/// PEM encoding trait.
+///
+/// This trait is automatically impl'd for any type which impls both
+/// [`Encode`] and [`PemLabel`].
+#[cfg(feature = "pem")]
+pub trait EncodePem: Encode + PemLabel {
+ /// Try to encode this type as PEM.
+ fn to_pem(&self, line_ending: LineEnding) -> Result<String>;
+}
+
+#[cfg(feature = "pem")]
+impl<T: Encode + PemLabel> EncodePem for T {
+ fn to_pem(&self, line_ending: LineEnding) -> Result<String> {
+ let der_len = usize::try_from(self.encoded_len()?)?;
+ let pem_len = pem::encapsulated_len(Self::PEM_LABEL, line_ending, der_len)?;
+
+ let mut buf = vec![0u8; pem_len];
+ let mut writer = PemWriter::new(Self::PEM_LABEL, line_ending, &mut buf)?;
+ self.encode(&mut writer)?;
+
+ let actual_len = writer.finish()?;
+ buf.truncate(actual_len);
+ Ok(String::from_utf8(buf)?)
+ }
+}
+
+/// Encode the value part of a Tag-Length-Value encoded field, sans the [`Tag`]
+/// and [`Length`].
+pub trait EncodeValue {
+ /// Get the [`Header`] used to encode this value.
+ fn header(&self) -> Result<Header>
+ where
+ Self: Tagged,
+ {
+ Header::new(self.tag(), self.value_len()?)
+ }
+
+ /// Compute the length of this value (sans [`Tag`]+[`Length`] header) when
+ /// encoded as ASN.1 DER.
+ fn value_len(&self) -> Result<Length>;
+
+ /// Encode value (sans [`Tag`]+[`Length`] header) as ASN.1 DER using the
+ /// provided [`Writer`].
+ fn encode_value(&self, encoder: &mut impl Writer) -> Result<()>;
+}
+
+#[cfg(feature = "alloc")]
+impl<T> EncodeValue for Box<T>
+where
+ T: EncodeValue,
+{
+ fn value_len(&self) -> Result<Length> {
+ T::value_len(self)
+ }
+ fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
+ T::encode_value(self, writer)
+ }
+}