1use crate::{
14 grammar, Base64Decoder, Error, Result, BASE64_WRAP_WIDTH, POST_ENCAPSULATION_BOUNDARY,
15 PRE_ENCAPSULATION_BOUNDARY,
16};
17use core::str;
18
19#[cfg(feature = "alloc")]
20use alloc::vec::Vec;
21
22#[cfg(feature = "std")]
23use std::io;
24
25pub fn decode<'i, 'o>(pem: &'i [u8], buf: &'o mut [u8]) -> Result<(&'i str, &'o [u8])> {
31 let mut decoder = Decoder::new(pem).map_err(|e| check_for_headers(pem, e))?;
32 let type_label = decoder.type_label();
33 let buf = buf
34 .get_mut(..decoder.remaining_len())
35 .ok_or(Error::Length)?;
36 let decoded = decoder.decode(buf).map_err(|e| check_for_headers(pem, e))?;
37
38 if decoder.base64.is_finished() {
39 Ok((type_label, decoded))
40 } else {
41 Err(Error::Length)
42 }
43}
44
45#[cfg(feature = "alloc")]
48#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
49pub fn decode_vec(pem: &[u8]) -> Result<(&str, Vec<u8>)> {
50 let mut decoder = Decoder::new(pem).map_err(|e| check_for_headers(pem, e))?;
51 let type_label = decoder.type_label();
52 let mut buf = Vec::new();
53 decoder
54 .decode_to_end(&mut buf)
55 .map_err(|e| check_for_headers(pem, e))?;
56 Ok((type_label, buf))
57}
58
59pub fn decode_label(pem: &[u8]) -> Result<&str> {
63 Ok(Encapsulation::try_from(pem)?.label())
64}
65
66#[derive(Clone)]
71pub struct Decoder<'i> {
72 type_label: &'i str,
74
75 base64: Base64Decoder<'i>,
77}
78
79impl<'i> Decoder<'i> {
80 pub fn new(pem: &'i [u8]) -> Result<Self> {
84 Self::new_wrapped(pem, BASE64_WRAP_WIDTH)
85 }
86
87 pub fn new_wrapped(pem: &'i [u8], line_width: usize) -> Result<Self> {
89 let encapsulation = Encapsulation::try_from(pem)?;
90 let type_label = encapsulation.label();
91 let base64 = Base64Decoder::new_wrapped(encapsulation.encapsulated_text, line_width)?;
92 Ok(Self { type_label, base64 })
93 }
94
95 pub fn type_label(&self) -> &'i str {
97 self.type_label
98 }
99
100 pub fn decode<'o>(&mut self, buf: &'o mut [u8]) -> Result<&'o [u8]> {
105 Ok(self.base64.decode(buf)?)
106 }
107
108 #[cfg(feature = "alloc")]
110 #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
111 pub fn decode_to_end<'o>(&mut self, buf: &'o mut Vec<u8>) -> Result<&'o [u8]> {
112 Ok(self.base64.decode_to_end(buf)?)
113 }
114
115 pub fn remaining_len(&self) -> usize {
117 self.base64.remaining_len()
118 }
119
120 pub fn is_finished(&self) -> bool {
122 self.base64.is_finished()
123 }
124}
125
126impl<'i> From<Decoder<'i>> for Base64Decoder<'i> {
127 fn from(decoder: Decoder<'i>) -> Base64Decoder<'i> {
128 decoder.base64
129 }
130}
131
132#[cfg(feature = "std")]
133#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
134impl<'i> io::Read for Decoder<'i> {
135 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
136 self.base64.read(buf)
137 }
138
139 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
140 self.base64.read_to_end(buf)
141 }
142
143 fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
144 self.base64.read_exact(buf)
145 }
146}
147
148#[derive(Copy, Clone, Debug)]
160struct Encapsulation<'a> {
161 label: &'a str,
178
179 encapsulated_text: &'a [u8],
184}
185
186impl<'a> Encapsulation<'a> {
187 pub fn parse(data: &'a [u8]) -> Result<Self> {
190 let data = grammar::strip_preamble(data)?;
192
193 let data = data
195 .strip_prefix(PRE_ENCAPSULATION_BOUNDARY)
196 .ok_or(Error::PreEncapsulationBoundary)?;
197
198 let (label, body) = grammar::split_label(data).ok_or(Error::Label)?;
199
200 let mut body = match grammar::strip_trailing_eol(body).unwrap_or(body) {
201 [head @ .., b'-', b'-', b'-', b'-', b'-'] => head,
202 _ => return Err(Error::PreEncapsulationBoundary),
203 };
204
205 for &slice in [POST_ENCAPSULATION_BOUNDARY, label.as_bytes()].iter().rev() {
207 if !body.ends_with(slice) {
210 return Err(Error::PostEncapsulationBoundary);
211 }
212
213 let len = body.len().checked_sub(slice.len()).ok_or(Error::Length)?;
214 body = body.get(..len).ok_or(Error::PostEncapsulationBoundary)?;
215 }
216
217 let encapsulated_text =
218 grammar::strip_trailing_eol(body).ok_or(Error::PostEncapsulationBoundary)?;
219
220 Ok(Self {
221 label,
222 encapsulated_text,
223 })
224 }
225
226 pub fn label(self) -> &'a str {
228 self.label
229 }
230}
231
232impl<'a> TryFrom<&'a [u8]> for Encapsulation<'a> {
233 type Error = Error;
234
235 fn try_from(bytes: &'a [u8]) -> Result<Self> {
236 Self::parse(bytes)
237 }
238}
239
240fn check_for_headers(pem: &[u8], err: Error) -> Error {
244 if err == Error::Base64(base64ct::Error::InvalidEncoding)
245 && pem.iter().any(|&b| b == grammar::CHAR_COLON)
246 {
247 Error::HeaderDisallowed
248 } else {
249 err
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::Encapsulation;
256
257 #[test]
258 fn pkcs8_example() {
259 let pem = include_bytes!("../tests/examples/pkcs8.pem");
260 let encapsulation = Encapsulation::parse(pem).unwrap();
261 assert_eq!(encapsulation.label, "PRIVATE KEY");
262
263 assert_eq!(
264 encapsulation.encapsulated_text,
265 &[
266 77, 67, 52, 67, 65, 81, 65, 119, 66, 81, 89, 68, 75, 50, 86, 119, 66, 67, 73, 69,
267 73, 66, 102, 116, 110, 72, 80, 112, 50, 50, 83, 101, 119, 89, 109, 109, 69, 111,
268 77, 99, 88, 56, 86, 119, 73, 52, 73, 72, 119, 97, 113, 100, 43, 57, 76, 70, 80,
269 106, 47, 49, 53, 101, 113, 70
270 ]
271 );
272 }
273}