der/reader/
pem.rs

1//! Streaming PEM reader.
2
3use super::Reader;
4use crate::{Decode, Error, ErrorKind, Header, Length, Result};
5use core::cell::RefCell;
6
7#[allow(clippy::integer_arithmetic)]
8mod utils {
9    use crate::{Error, Length, Result};
10    use pem_rfc7468::Decoder;
11
12    #[derive(Clone)]
13    pub(super) struct BufReader<'i> {
14        /// Inner PEM decoder.
15        decoder: Decoder<'i>,
16
17        /// Remaining after base64 decoding
18        remaining: usize,
19
20        /// Read buffer
21        buf: [u8; BufReader::CAPACITY],
22
23        /// Position of the head in the buffer,
24        pos: usize,
25
26        /// Position of the tail in the buffer,
27        cap: usize,
28    }
29
30    impl<'i> BufReader<'i> {
31        const CAPACITY: usize = 256;
32
33        pub fn new(pem: &'i [u8]) -> Result<Self> {
34            let decoder = Decoder::new(pem)?;
35            let remaining = decoder.remaining_len();
36
37            Ok(Self {
38                decoder,
39                remaining,
40                buf: [0u8; 256],
41                pos: 0,
42                cap: 0,
43            })
44        }
45
46        pub fn remaining_len(&self) -> usize {
47            self.decoder.remaining_len() + self.cap - self.pos
48        }
49
50        fn fill_buffer(&mut self) -> Result<()> {
51            debug_assert!(self.pos <= self.cap);
52
53            if self.is_empty() {
54                self.pos = 0;
55                self.cap = 0;
56            }
57
58            let end = (self.cap + self.remaining).min(Self::CAPACITY);
59            let writable_slice = &mut self.buf[self.cap..end];
60            if writable_slice.is_empty() {
61                return Ok(());
62            }
63
64            let wrote = self.decoder.decode(writable_slice)?.len();
65            if wrote == 0 {
66                return Err(Error::incomplete(Length::try_from(self.pos)?));
67            }
68
69            self.cap += wrote;
70            self.remaining -= wrote;
71            debug_assert!(self.cap <= Self::CAPACITY);
72
73            Ok(())
74        }
75
76        /// Get the PEM label which will be used in the encapsulation boundaries
77        /// for this document.
78        pub fn type_label(&self) -> &'i str {
79            self.decoder.type_label()
80        }
81
82        fn is_empty(&self) -> bool {
83            self.pos == self.cap
84        }
85
86        fn as_slice(&self) -> &[u8] {
87            &self.buf[self.pos..self.cap]
88        }
89    }
90
91    impl<'i> BufReader<'i> {
92        pub fn peek_byte(&self) -> Option<u8> {
93            let s = self.as_slice();
94            s.first().copied()
95        }
96
97        pub fn copy_to_slice<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
98            let mut output_pos = 0;
99
100            while output_pos < buf.len() {
101                if self.is_empty() {
102                    self.fill_buffer()?;
103                }
104
105                let available = &self.buf[self.pos..self.cap];
106                let window_len = (buf.len() - output_pos).min(available.len());
107                let window = &mut buf[output_pos..output_pos + window_len];
108
109                window.copy_from_slice(&available[..window_len]);
110                self.pos += window_len;
111                output_pos += window_len;
112            }
113
114            // Don't leave the read buffer empty for peek_byte()
115            if self.is_empty() && self.decoder.remaining_len() != 0 {
116                self.fill_buffer()?
117            }
118
119            debug_assert_eq!(output_pos, buf.len());
120
121            Ok(buf)
122        }
123    }
124}
125
126/// `Reader` type which decodes PEM on-the-fly.
127#[cfg(feature = "pem")]
128#[derive(Clone)]
129pub struct PemReader<'i> {
130    /// Inner PEM decoder wrapped in a BufReader.
131    reader: RefCell<utils::BufReader<'i>>,
132
133    /// Input length (in bytes after Base64 decoding).
134    input_len: Length,
135
136    /// Position in the input buffer (in bytes after Base64 decoding).
137    position: Length,
138}
139
140#[cfg(feature = "pem")]
141impl<'i> PemReader<'i> {
142    /// Create a new PEM reader which decodes data on-the-fly.
143    ///
144    /// Uses the default 64-character line wrapping.
145    pub fn new(pem: &'i [u8]) -> Result<Self> {
146        let reader = utils::BufReader::new(pem)?;
147        let input_len = Length::try_from(reader.remaining_len())?;
148
149        Ok(Self {
150            reader: RefCell::new(reader),
151            input_len,
152            position: Length::ZERO,
153        })
154    }
155
156    /// Get the PEM label which will be used in the encapsulation boundaries
157    /// for this document.
158    pub fn type_label(&self) -> &'i str {
159        self.reader.borrow().type_label()
160    }
161}
162
163#[cfg(feature = "pem")]
164impl<'i> Reader<'i> for PemReader<'i> {
165    fn input_len(&self) -> Length {
166        self.input_len
167    }
168
169    fn peek_byte(&self) -> Option<u8> {
170        if self.is_finished() {
171            None
172        } else {
173            self.reader.borrow().peek_byte()
174        }
175    }
176
177    fn peek_header(&self) -> Result<Header> {
178        if self.is_finished() {
179            Err(Error::incomplete(self.offset()))
180        } else {
181            Header::decode(&mut self.clone())
182        }
183    }
184
185    fn position(&self) -> Length {
186        self.position
187    }
188
189    fn read_slice(&mut self, _len: Length) -> Result<&'i [u8]> {
190        // Can't borrow from PEM because it requires decoding
191        Err(ErrorKind::Reader.into())
192    }
193
194    fn read_into<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
195        let bytes = self.reader.borrow_mut().copy_to_slice(buf)?;
196
197        self.position = (self.position + bytes.len())?;
198
199        debug_assert_eq!(
200            self.position,
201            (self.input_len - Length::try_from(self.reader.borrow().remaining_len())?)?
202        );
203
204        Ok(bytes)
205    }
206}