summaryrefslogtreecommitdiffstats
path: root/vendor/der/src/reader/pem.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/der/src/reader/pem.rs')
-rw-r--r--vendor/der/src/reader/pem.rs206
1 files changed, 206 insertions, 0 deletions
diff --git a/vendor/der/src/reader/pem.rs b/vendor/der/src/reader/pem.rs
new file mode 100644
index 0000000..f11341a
--- /dev/null
+++ b/vendor/der/src/reader/pem.rs
@@ -0,0 +1,206 @@
+//! Streaming PEM reader.
+
+use super::Reader;
+use crate::{Decode, Error, ErrorKind, Header, Length, Result};
+use core::cell::RefCell;
+
+#[allow(clippy::integer_arithmetic)]
+mod utils {
+ use crate::{Error, Length, Result};
+ use pem_rfc7468::Decoder;
+
+ #[derive(Clone)]
+ pub(super) struct BufReader<'i> {
+ /// Inner PEM decoder.
+ decoder: Decoder<'i>,
+
+ /// Remaining after base64 decoding
+ remaining: usize,
+
+ /// Read buffer
+ buf: [u8; BufReader::CAPACITY],
+
+ /// Position of the head in the buffer,
+ pos: usize,
+
+ /// Position of the tail in the buffer,
+ cap: usize,
+ }
+
+ impl<'i> BufReader<'i> {
+ const CAPACITY: usize = 256;
+
+ pub fn new(pem: &'i [u8]) -> Result<Self> {
+ let decoder = Decoder::new(pem)?;
+ let remaining = decoder.remaining_len();
+
+ Ok(Self {
+ decoder,
+ remaining,
+ buf: [0u8; 256],
+ pos: 0,
+ cap: 0,
+ })
+ }
+
+ pub fn remaining_len(&self) -> usize {
+ self.decoder.remaining_len() + self.cap - self.pos
+ }
+
+ fn fill_buffer(&mut self) -> Result<()> {
+ debug_assert!(self.pos <= self.cap);
+
+ if self.is_empty() {
+ self.pos = 0;
+ self.cap = 0;
+ }
+
+ let end = (self.cap + self.remaining).min(Self::CAPACITY);
+ let writable_slice = &mut self.buf[self.cap..end];
+ if writable_slice.is_empty() {
+ return Ok(());
+ }
+
+ let wrote = self.decoder.decode(writable_slice)?.len();
+ if wrote == 0 {
+ return Err(Error::incomplete(Length::try_from(self.pos)?));
+ }
+
+ self.cap += wrote;
+ self.remaining -= wrote;
+ debug_assert!(self.cap <= Self::CAPACITY);
+
+ Ok(())
+ }
+
+ /// Get the PEM label which will be used in the encapsulation boundaries
+ /// for this document.
+ pub fn type_label(&self) -> &'i str {
+ self.decoder.type_label()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.pos == self.cap
+ }
+
+ fn as_slice(&self) -> &[u8] {
+ &self.buf[self.pos..self.cap]
+ }
+ }
+
+ impl<'i> BufReader<'i> {
+ pub fn peek_byte(&self) -> Option<u8> {
+ let s = self.as_slice();
+ s.first().copied()
+ }
+
+ pub fn copy_to_slice<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
+ let mut output_pos = 0;
+
+ while output_pos < buf.len() {
+ if self.is_empty() {
+ self.fill_buffer()?;
+ }
+
+ let available = &self.buf[self.pos..self.cap];
+ let window_len = (buf.len() - output_pos).min(available.len());
+ let window = &mut buf[output_pos..output_pos + window_len];
+
+ window.copy_from_slice(&available[..window_len]);
+ self.pos += window_len;
+ output_pos += window_len;
+ }
+
+ // Don't leave the read buffer empty for peek_byte()
+ if self.is_empty() && self.decoder.remaining_len() != 0 {
+ self.fill_buffer()?
+ }
+
+ debug_assert_eq!(output_pos, buf.len());
+
+ Ok(buf)
+ }
+ }
+}
+
+/// `Reader` type which decodes PEM on-the-fly.
+#[cfg(feature = "pem")]
+#[derive(Clone)]
+pub struct PemReader<'i> {
+ /// Inner PEM decoder wrapped in a BufReader.
+ reader: RefCell<utils::BufReader<'i>>,
+
+ /// Input length (in bytes after Base64 decoding).
+ input_len: Length,
+
+ /// Position in the input buffer (in bytes after Base64 decoding).
+ position: Length,
+}
+
+#[cfg(feature = "pem")]
+impl<'i> PemReader<'i> {
+ /// Create a new PEM reader which decodes data on-the-fly.
+ ///
+ /// Uses the default 64-character line wrapping.
+ pub fn new(pem: &'i [u8]) -> Result<Self> {
+ let reader = utils::BufReader::new(pem)?;
+ let input_len = Length::try_from(reader.remaining_len())?;
+
+ Ok(Self {
+ reader: RefCell::new(reader),
+ input_len,
+ position: Length::ZERO,
+ })
+ }
+
+ /// Get the PEM label which will be used in the encapsulation boundaries
+ /// for this document.
+ pub fn type_label(&self) -> &'i str {
+ self.reader.borrow().type_label()
+ }
+}
+
+#[cfg(feature = "pem")]
+impl<'i> Reader<'i> for PemReader<'i> {
+ fn input_len(&self) -> Length {
+ self.input_len
+ }
+
+ fn peek_byte(&self) -> Option<u8> {
+ if self.is_finished() {
+ None
+ } else {
+ self.reader.borrow().peek_byte()
+ }
+ }
+
+ fn peek_header(&self) -> Result<Header> {
+ if self.is_finished() {
+ Err(Error::incomplete(self.offset()))
+ } else {
+ Header::decode(&mut self.clone())
+ }
+ }
+
+ fn position(&self) -> Length {
+ self.position
+ }
+
+ fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> {
+ // Can't borrow from PEM because it requires decoding
+ Err(ErrorKind::Reader.into())
+ }
+
+ fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
+ let bytes = self.reader.borrow_mut().copy_to_slice(buf)?;
+
+ self.position = (self.position + bytes.len())?;
+
+ debug_assert_eq!(
+ self.position,
+ (self.input_len - Length::try_from(self.reader.borrow().remaining_len())?)?
+ );
+
+ Ok(bytes)
+ }
+}