summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/writer
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
commit2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch)
tree033cc839730fda84ff08db877037977be94e5e3a /vendor/der/src/writer
parentInitial commit. (diff)
downloadcargo-upstream.tar.xz
cargo-upstream.zip
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/der/src/writer')
-rw-r--r--vendor/der/src/writer/pem.rs41
-rw-r--r--vendor/der/src/writer/slice.rs149
2 files changed, 190 insertions, 0 deletions
diff --git a/vendor/der/src/writer/pem.rs b/vendor/der/src/writer/pem.rs
new file mode 100644
index 0000000..87a6f8f
--- /dev/null
+++ b/vendor/der/src/writer/pem.rs
@@ -0,0 +1,41 @@
+//! Streaming PEM writer.
+
+use super::Writer;
+use crate::Result;
+use pem_rfc7468::{Encoder, LineEnding};
+
+/// `Writer` type which outputs PEM-encoded data.
+pub struct PemWriter<'w>(Encoder<'static, 'w>);
+
+impl<'w> PemWriter<'w> {
+ /// Create a new PEM writer which outputs into the provided buffer.
+ ///
+ /// Uses the default 64-character line wrapping.
+ pub fn new(
+ type_label: &'static str,
+ line_ending: LineEnding,
+ out: &'w mut [u8],
+ ) -> Result<Self> {
+ Ok(Self(Encoder::new(type_label, line_ending, out)?))
+ }
+
+ /// Get the PEM label which will be used in the encapsulation boundaries
+ /// for this document.
+ pub fn type_label(&self) -> &'static str {
+ self.0.type_label()
+ }
+
+ /// Finish encoding PEM, writing the post-encapsulation boundary.
+ ///
+ /// On success, returns the total number of bytes written to the output buffer.
+ pub fn finish(self) -> Result<usize> {
+ Ok(self.0.finish()?)
+ }
+}
+
+impl Writer for PemWriter<'_> {
+ fn write(&mut self, slice: &[u8]) -> Result<()> {
+ self.0.encode(slice)?;
+ Ok(())
+ }
+}
diff --git a/vendor/der/src/writer/slice.rs b/vendor/der/src/writer/slice.rs
new file mode 100644
index 0000000..5dafe99
--- /dev/null
+++ b/vendor/der/src/writer/slice.rs
@@ -0,0 +1,149 @@
+//! Slice writer.
+
+use crate::{
+ asn1::*, Encode, EncodeValue, ErrorKind, Header, Length, Result, Tag, TagMode, TagNumber,
+ Tagged, Writer,
+};
+
+/// [`Writer`] which encodes DER into a mutable output byte slice.
+#[derive(Debug)]
+pub struct SliceWriter<'a> {
+ /// Buffer into which DER-encoded message is written
+ bytes: &'a mut [u8],
+
+ /// Has the encoding operation failed?
+ failed: bool,
+
+ /// Total number of bytes written to buffer so far
+ position: Length,
+}
+
+impl<'a> SliceWriter<'a> {
+ /// Create a new encoder with the given byte slice as a backing buffer.
+ pub fn new(bytes: &'a mut [u8]) -> Self {
+ Self {
+ bytes,
+ failed: false,
+ position: Length::ZERO,
+ }
+ }
+
+ /// Encode a value which impls the [`Encode`] trait.
+ pub fn encode<T: Encode>(&mut self, encodable: &T) -> Result<()> {
+ if self.is_failed() {
+ self.error(ErrorKind::Failed)?;
+ }
+
+ encodable.encode(self).map_err(|e| {
+ self.failed = true;
+ e.nested(self.position)
+ })
+ }
+
+ /// Return an error with the given [`ErrorKind`], annotating it with
+ /// context about where the error occurred.
+ pub fn error<T>(&mut self, kind: ErrorKind) -> Result<T> {
+ self.failed = true;
+ Err(kind.at(self.position))
+ }
+
+ /// Did the decoding operation fail due to an error?
+ pub fn is_failed(&self) -> bool {
+ self.failed
+ }
+
+ /// Finish encoding to the buffer, returning a slice containing the data
+ /// written to the buffer.
+ pub fn finish(self) -> Result<&'a [u8]> {
+ let position = self.position;
+
+ if self.is_failed() {
+ return Err(ErrorKind::Failed.at(position));
+ }
+
+ self.bytes
+ .get(..usize::try_from(position)?)
+ .ok_or_else(|| ErrorKind::Overlength.at(position))
+ }
+
+ /// Encode a `CONTEXT-SPECIFIC` field with the provided tag number and mode.
+ pub fn context_specific<T>(
+ &mut self,
+ tag_number: TagNumber,
+ tag_mode: TagMode,
+ value: &T,
+ ) -> Result<()>
+ where
+ T: EncodeValue + Tagged,
+ {
+ ContextSpecificRef {
+ tag_number,
+ tag_mode,
+ value,
+ }
+ .encode(self)
+ }
+
+ /// Encode an ASN.1 `SEQUENCE` of the given length.
+ ///
+ /// Spawns a nested slice writer which is expected to be exactly the
+ /// specified length upon completion.
+ pub fn sequence<F>(&mut self, length: Length, f: F) -> Result<()>
+ where
+ F: FnOnce(&mut SliceWriter<'_>) -> Result<()>,
+ {
+ Header::new(Tag::Sequence, length).and_then(|header| header.encode(self))?;
+
+ let mut nested_encoder = SliceWriter::new(self.reserve(length)?);
+ f(&mut nested_encoder)?;
+
+ if nested_encoder.finish()?.len() == usize::try_from(length)? {
+ Ok(())
+ } else {
+ self.error(ErrorKind::Length { tag: Tag::Sequence })
+ }
+ }
+
+ /// Reserve a portion of the internal buffer, updating the internal cursor
+ /// position and returning a mutable slice.
+ fn reserve(&mut self, len: impl TryInto<Length>) -> Result<&mut [u8]> {
+ if self.is_failed() {
+ return Err(ErrorKind::Failed.at(self.position));
+ }
+
+ let len = len
+ .try_into()
+ .or_else(|_| self.error(ErrorKind::Overflow))?;
+
+ let end = (self.position + len).or_else(|e| self.error(e.kind()))?;
+ let slice = self
+ .bytes
+ .get_mut(self.position.try_into()?..end.try_into()?)
+ .ok_or_else(|| ErrorKind::Overlength.at(end))?;
+
+ self.position = end;
+ Ok(slice)
+ }
+}
+
+impl<'a> Writer for SliceWriter<'a> {
+ fn write(&mut self, slice: &[u8]) -> Result<()> {
+ self.reserve(slice.len())?.copy_from_slice(slice);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::SliceWriter;
+ use crate::{Encode, ErrorKind, Length};
+
+ #[test]
+ fn overlength_message() {
+ let mut buffer = [];
+ let mut writer = SliceWriter::new(&mut buffer);
+ let err = false.encode(&mut writer).err().unwrap();
+ assert_eq!(err.kind(), ErrorKind::Overlength);
+ assert_eq!(err.position(), Some(Length::ONE));
+ }
+}