1 //! ASCII Armor.
2 //!
3 //! This module deals with ASCII Armored data (see [Section 6 of RFC
4 //! 4880]).
5 //!
6 //!   [Section 6 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-6
7 //!
8 //! # Scope
9 //!
10 //! This implements a subset of the ASCII Armor specification.  Not
11 //! supported multipart messages.
12 //!
13 //! # Memory allocations
14 //!
15 //! Both the reader and the writer allocate memory in the order of the
16 //! size of chunks read or written.
17 //!
18 //! # Examples
19 //!
20 //! ```rust, no_run
21 //! use sequoia_openpgp as openpgp;
22 //! use std::fs::File;
23 //! use openpgp::armor::{Reader, ReaderMode, Kind};
24 //!
25 //! let mut file = File::open("somefile.asc").unwrap();
26 //! let mut r = Reader::new(&mut file, ReaderMode::Tolerant(Some(Kind::File)));
27 //! ```
28 
29 extern crate base64;
30 use buffered_reader::BufferedReader;
31 use std::io::{Cursor, Read, Write};
32 use std::io::{Result, Error, ErrorKind};
33 use std::path::Path;
34 use std::cmp;
35 use std::str;
36 use std::borrow::Cow;
37 
38 #[cfg(any(test, feature = "quickcheck"))]
39 use quickcheck::{Arbitrary, Gen};
40 
41 use crate::vec_truncate;
42 use crate::packet::prelude::*;
43 use crate::packet::header::{BodyLength, CTBNew, CTBOld};
44 use crate::serialize::MarshalInto;
45 
46 /// The encoded output stream must be represented in lines of no more
47 /// than 76 characters each (see (see [RFC 4880, section
48 /// 6.3](https://tools.ietf.org/html/rfc4880#section-6.3).  GnuPG uses
49 /// 64.
50 pub(crate) const LINE_LENGTH: usize = 64;
51 
52 const LINE_ENDING: &str = "\n";
53 
54 /// Specifies the type of data (see [RFC 4880, section 6.2]).
55 ///
56 /// [RFC 4880, section 6.2]: https://tools.ietf.org/html/rfc4880#section-6.2
57 #[derive(Copy, Clone, Debug, PartialEq)]
58 pub enum Kind {
59     /// A generic OpenPGP message.  (Since its structure hasn't been
60     /// validated, in this crate's terminology, this is just a
61     /// `PacketPile`.)
62     Message,
63     /// A certificate.
64     PublicKey,
65     /// A transferable secret key.
66     SecretKey,
67     /// A detached signature.
68     Signature,
69     /// A generic file.  This is a GnuPG extension.
70     File,
71 }
72 
73 #[cfg(any(test, feature = "quickcheck"))]
74 impl Arbitrary for Kind {
arbitrary<G: Gen>(g: &mut G) -> Self75     fn arbitrary<G: Gen>(g: &mut G) -> Self {
76         use self::Kind::*;
77         match u8::arbitrary(g) % 5 {
78             0 => Message,
79             1 => PublicKey,
80             2 => SecretKey,
81             3 => Signature,
82             4 => File,
83             _ => unreachable!(),
84         }
85     }
86 }
87 
88 impl Kind {
89     /// Autodetects the kind of data.
detect(blurb: &[u8]) -> Option<Self>90     fn detect(blurb: &[u8]) -> Option<Self> {
91         if blurb.len() < "-----BEGIN PGP MESSAGE-----".len()
92             || ! blurb.starts_with(b"-----BEGIN PGP ")
93         {
94             return None;
95         }
96 
97         let kind = &blurb[15..];
98         if kind.starts_with(b"MESSAGE-----") {
99             Some(Kind::Message)
100         } else if kind.starts_with(b"PUBLIC KEY BLOCK-----") {
101             Some(Kind::PublicKey)
102         } else if kind.starts_with(b"PRIVATE KEY BLOCK-----") {
103             Some(Kind::SecretKey)
104         } else if kind.starts_with(b"SIGNATURE-----") {
105             Some(Kind::Signature)
106         } else if kind.starts_with(b"ARMORED FILE-----") {
107             Some(Kind::File)
108         } else {
109             None
110         }
111     }
112 
blurb(&self) -> &str113     fn blurb(&self) -> &str {
114         match self {
115             &Kind::Message => "MESSAGE",
116             &Kind::PublicKey => "PUBLIC KEY BLOCK",
117             &Kind::SecretKey => "PRIVATE KEY BLOCK",
118             &Kind::Signature => "SIGNATURE",
119             &Kind::File => "ARMORED FILE",
120         }
121     }
122 
begin(&self) -> String123     fn begin(&self) -> String {
124         format!("-----BEGIN PGP {}-----", self.blurb())
125     }
126 
end(&self) -> String127     fn end(&self) -> String {
128         format!("-----END PGP {}-----", self.blurb())
129     }
130 
131     /// Returns the length of the header.
132     ///
133     /// This does not include any trailing newline.  It is simply the
134     /// length of:
135     ///
136     /// ```text
137     /// -----BEGIN PGP BLUB -----
138     /// ```
header_len(&self) -> usize139     fn header_len(&self) -> usize {
140         "-----BEGIN PGP -----".len()
141             + self.blurb().len()
142     }
143 }
144 
145 /// A filter that applies ASCII Armor to the data written to it.
146 pub struct Writer<W: Write> {
147     sink: W,
148     kind: Kind,
149     stash: Vec<u8>,
150     column: usize,
151     crc: CRC,
152     header: Vec<u8>,
153     dirty: bool,
154 }
155 
156 impl<W: Write> Writer<W> {
157     /// Constructs a new filter for the given type of data.
158     ///
159     /// # Examples
160     ///
161     /// ```
162     /// use std::io::{Read, Write, Cursor};
163     /// use sequoia_openpgp as openpgp;
164     /// use openpgp::armor::{Writer, Kind};
165     ///
166     /// # fn main() -> std::io::Result<()> {
167     /// let mut writer = Writer::new(Vec::new(), Kind::File)?;
168     /// writer.write_all(b"Hello world!")?;
169     /// let buffer = writer.finalize()?;
170     /// assert_eq!(
171     ///     String::from_utf8_lossy(&buffer),
172     ///     "-----BEGIN PGP ARMORED FILE-----
173     ///
174     /// SGVsbG8gd29ybGQh
175     /// =s4Gu
176     /// -----END PGP ARMORED FILE-----
177     /// ");
178     /// # Ok(())
179     /// # }
180     /// ```
new(inner: W, kind: Kind) -> Result<Self>181     pub fn new(inner: W, kind: Kind) -> Result<Self> {
182         Self::with_headers(inner, kind, Option::<(&str, &str)>::None)
183     }
184 
185     /// Constructs a new filter for the given type of data.
186     ///
187     /// # Examples
188     ///
189     /// ```
190     /// use std::io::{Read, Write, Cursor};
191     /// use sequoia_openpgp as openpgp;
192     /// use openpgp::armor::{Writer, Kind};
193     ///
194     /// # fn main() -> std::io::Result<()> {
195     /// let mut writer = Writer::with_headers(Vec::new(), Kind::File,
196     ///     vec![("Key", "Value")])?;
197     /// writer.write_all(b"Hello world!")?;
198     /// let buffer = writer.finalize()?;
199     /// assert_eq!(
200     ///     String::from_utf8_lossy(&buffer),
201     ///     "-----BEGIN PGP ARMORED FILE-----
202     /// Key: Value
203     ///
204     /// SGVsbG8gd29ybGQh
205     /// =s4Gu
206     /// -----END PGP ARMORED FILE-----
207     /// ");
208     /// # Ok(())
209     /// # }
210     /// ```
with_headers<I, K, V>(inner: W, kind: Kind, headers: I) -> Result<Self> where I: IntoIterator<Item = (K, V)>, K: AsRef<str>, V: AsRef<str>,211     pub fn with_headers<I, K, V>(inner: W, kind: Kind, headers: I)
212                                  -> Result<Self>
213         where I: IntoIterator<Item = (K, V)>,
214               K: AsRef<str>,
215               V: AsRef<str>,
216     {
217         let mut w = Writer {
218             sink: inner,
219             kind,
220             stash: Vec::<u8>::with_capacity(2),
221             column: 0,
222             crc: CRC::new(),
223             header: Vec::with_capacity(128),
224             dirty: false,
225         };
226 
227         {
228             let mut cur = Cursor::new(&mut w.header);
229             write!(&mut cur, "{}{}", kind.begin(), LINE_ENDING)?;
230 
231             for h in headers {
232                 write!(&mut cur, "{}: {}{}", h.0.as_ref(), h.1.as_ref(),
233                        LINE_ENDING)?;
234             }
235 
236             // A blank line separates the headers from the body.
237             write!(&mut cur, "{}", LINE_ENDING)?;
238         }
239 
240         Ok(w)
241     }
242 
243     /// Returns a reference to the inner writer.
get_ref(&self) -> &W244     pub fn get_ref(&self) -> &W {
245         &self.sink
246     }
247 
248     /// Returns a mutable reference to the inner writer.
get_mut(&mut self) -> &mut W249     pub fn get_mut(&mut self) -> &mut W {
250         &mut self.sink
251     }
252 
finalize_headers(&mut self) -> Result<()>253     fn finalize_headers(&mut self) -> Result<()> {
254         if ! self.dirty {
255             self.dirty = true;
256             self.sink.write_all(&self.header)?;
257             // Release memory.
258             crate::vec_truncate(&mut self.header, 0);
259             self.header.shrink_to_fit();
260         }
261         Ok(())
262     }
263 
264     /// Writes the footer.
265     ///
266     /// This function needs to be called explicitly before the writer is dropped.
finalize(mut self) -> Result<W>267     pub fn finalize(mut self) -> Result<W> {
268         if ! self.dirty {
269             // No data was written to us, don't emit anything.
270             return Ok(self.sink);
271         }
272         self.finalize_armor()?;
273         Ok(self.sink)
274     }
275 
276     /// Writes the footer.
finalize_armor(&mut self) -> Result<()>277     fn finalize_armor(&mut self) -> Result<()> {
278         if ! self.dirty {
279             // No data was written to us, don't emit anything.
280             return Ok(());
281         }
282         self.finalize_headers()?;
283 
284         // Write any stashed bytes and pad.
285         if self.stash.len() > 0 {
286             self.sink.write_all(base64::encode_config(
287                 &self.stash, base64::STANDARD).as_bytes())?;
288             self.column += 4;
289         }
290 
291         // Inserts a line break if necessary.
292         //
293         // Unfortunately, we cannot use
294         //self.linebreak()?;
295         //
296         // Therefore, we inline it here.  This is a bit sad.
297         assert!(self.column <= LINE_LENGTH);
298         if self.column == LINE_LENGTH {
299             write!(self.sink, "{}", LINE_ENDING)?;
300             self.column = 0;
301         }
302 
303         if self.column > 0 {
304             write!(self.sink, "{}", LINE_ENDING)?;
305         }
306 
307         // 24-bit CRC
308         let crc = self.crc.finalize();
309         let bytes = &crc.to_be_bytes()[1..4];
310 
311         // CRC and footer.
312         write!(self.sink, "={}{}{}{}",
313                base64::encode_config(&bytes, base64::STANDARD_NO_PAD),
314                LINE_ENDING, self.kind.end(), LINE_ENDING)?;
315 
316         self.dirty = false;
317         Ok(())
318     }
319 
320     /// Inserts a line break if necessary.
linebreak(&mut self) -> Result<()>321     fn linebreak(&mut self) -> Result<()> {
322         assert!(self.column <= LINE_LENGTH);
323         if self.column == LINE_LENGTH {
324             write!(self.sink, "{}", LINE_ENDING)?;
325             self.column = 0;
326         }
327         Ok(())
328     }
329 }
330 
331 impl<W: Write> Write for Writer<W> {
write(&mut self, buf: &[u8]) -> Result<usize>332     fn write(&mut self, buf: &[u8]) -> Result<usize> {
333         self.finalize_headers()?;
334 
335         // Update CRC on the unencoded data.
336         self.crc.update(buf);
337 
338         let mut input = buf;
339         let mut written = 0;
340 
341         // First of all, if there are stashed bytes, fill the stash
342         // and encode it.  If writing out the stash fails below, we
343         // might end up with a stash of size 3.
344         assert!(self.stash.len() <= 3);
345         if self.stash.len() > 0 {
346             while self.stash.len() < 3 {
347                 if input.len() == 0 {
348                     /* We exhausted the input.  Return now, any
349                      * stashed bytes are encoded when finalizing the
350                      * writer.  */
351                     return Ok(written);
352                 }
353                 self.stash.push(input[0]);
354                 input = &input[1..];
355                 written += 1;
356             }
357             assert_eq!(self.stash.len(), 3);
358 
359             // If this fails for some reason, and the caller retries
360             // the write, we might end up with a stash of size 3.
361             self.sink
362                 .write_all(base64::encode_config(
363                     &self.stash, base64::STANDARD_NO_PAD).as_bytes())?;
364             self.column += 4;
365             self.linebreak()?;
366             crate::vec_truncate(&mut self.stash, 0);
367         }
368 
369         // Ensure that a multiple of 3 bytes are encoded, stash the
370         // rest from the end of input.
371         while input.len() % 3 > 0 {
372             self.stash.push(input[input.len()-1]);
373             input = &input[..input.len()-1];
374             written += 1;
375         }
376         // We popped values from the end of the input, fix the order.
377         self.stash.reverse();
378         assert!(self.stash.len() < 3);
379 
380         // We know that we have a multiple of 3 bytes, encode them and write them out.
381         assert!(input.len() % 3 == 0);
382         let encoded = base64::encode_config(input, base64::STANDARD_NO_PAD);
383         written += input.len();
384         let mut enc = encoded.as_bytes();
385         while enc.len() > 0 {
386             let n = cmp::min(LINE_LENGTH - self.column, enc.len());
387             self.sink
388                 .write_all(&enc[..n])?;
389             enc = &enc[n..];
390             self.column += n;
391             self.linebreak()?;
392         }
393 
394         assert_eq!(written, buf.len());
395         Ok(written)
396     }
397 
flush(&mut self) -> Result<()>398     fn flush(&mut self) -> Result<()> {
399         self.sink.flush()
400     }
401 }
402 
403 /// How an ArmorReader should act.
404 #[derive(Debug, Clone, Copy, PartialEq)]
405 pub enum ReaderMode {
406     /// Makes the armor reader tolerant of simple errors.
407     ///
408     /// The armor reader will be tolerant of common formatting errors,
409     /// such as incorrect line folding, but the armor header line
410     /// (e.g., `----- BEGIN PGP MESSAGE -----`) and the footer must be
411     /// intact.
412     ///
413     /// If a Kind is specified, then only ASCII Armor blocks with the
414     /// appropriate header are recognized.
415     ///
416     /// This mode is appropriate when reading from a file.
417     Tolerant(Option<Kind>),
418 
419     /// Makes the armor reader very tolerant of errors.
420     ///
421     /// Unlike in `Tolerant` mode, in this mode, the armor reader
422     /// doesn't require an armor header line.  Instead, it examines
423     /// chunks that look like valid base64 data, and attempts to parse
424     /// them.
425     ///
426     /// Although this mode looks for OpenPGP fingerprints before
427     /// invoking the full parser, due to the number of false
428     /// positives, this mode of operation is CPU intense, particularly
429     /// on large text files.  It is primarily appropriate when reading
430     /// text that the user cut and pasted into a text area.
431     VeryTolerant,
432 }
433 
434 /// A filter that strips ASCII Armor from a stream of data.
435 pub struct Reader<'a> {
436     source: Box<dyn BufferedReader<()> + 'a>,
437     kind: Option<Kind>,
438     mode: ReaderMode,
439     buffer: Vec<u8>,
440     crc: CRC,
441     expect_crc: Option<u32>,
442     initialized: bool,
443     headers: Vec<(String, String)>,
444     finalized: bool,
445     prefix_len: usize,
446     prefix_remaining: usize,
447 }
448 
449 impl Default for ReaderMode {
default() -> Self450     fn default() -> Self {
451         ReaderMode::Tolerant(None)
452     }
453 }
454 
455 impl<'a> Reader<'a> {
456     /// Constructs a new filter for the given type of data.
457     ///
458     /// [ASCII Armor], designed to protect OpenPGP data in transit,
459     /// has been a source of problems if the armor structure is
460     /// damaged.  For example, copying data manually from one program
461     /// to another might introduce or drop newlines.
462     ///
463     /// By default, the reader operates in robust mode.  It will
464     /// extract the first armored OpenPGP data block it can find, even
465     /// if the armor frame is damaged, or missing.
466     ///
467     /// To select strict mode, specify a kind argument.  In strict
468     /// mode, the reader will match on the armor frame.  The reader
469     /// ignores any data in front of the Armor Header Line, as long as
470     /// the line the header is only prefixed by whitespace.
471     ///
472     ///   [ASCII Armor]: https://tools.ietf.org/html/rfc4880#section-6.2
473     ///
474     /// # Examples
475     ///
476     /// ```
477     /// use std::io::{self, Read};
478     /// use sequoia_openpgp as openpgp;
479     /// use openpgp::Message;
480     /// use openpgp::armor::{Reader, ReaderMode};
481     /// use openpgp::parse::Parse;
482     ///
483     /// # fn main() -> openpgp::Result<()> {
484     /// let data = "yxJiAAAAAABIZWxsbyB3b3JsZCE="; // base64 over literal data packet
485     ///
486     /// let mut cursor = io::Cursor::new(&data);
487     /// let mut reader = Reader::new(&mut cursor, ReaderMode::VeryTolerant);
488     ///
489     /// let mut buf = Vec::new();
490     /// reader.read_to_end(&mut buf)?;
491     ///
492     /// let message = Message::from_bytes(&buf)?;
493     /// assert_eq!(message.body().unwrap().body(),
494     ///            b"Hello world!");
495     /// # Ok(())
496     /// # }
497     /// ```
498     ///
499     /// Or, in strict mode:
500     ///
501     /// ```
502     /// use std::io::{self, Result, Read};
503     /// use sequoia_openpgp as openpgp;
504     /// use openpgp::armor::{Reader, ReaderMode, Kind};
505     ///
506     /// # fn main() -> Result<()> {
507     /// let data =
508     ///     "-----BEGIN PGP ARMORED FILE-----
509     ///
510     ///      SGVsbG8gd29ybGQh
511     ///      =s4Gu
512     ///      -----END PGP ARMORED FILE-----";
513     ///
514     /// let mut cursor = io::Cursor::new(&data);
515     /// let mut reader = Reader::new(&mut cursor, ReaderMode::Tolerant(Some(Kind::File)));
516     ///
517     /// let mut content = String::new();
518     /// reader.read_to_string(&mut content)?;
519     /// assert_eq!(content, "Hello world!");
520     /// assert_eq!(reader.kind(), Some(Kind::File));
521     /// # Ok(())
522     /// # }
523     /// ```
new<R, M>(inner: R, mode: M) -> Self where R: 'a + Read, M: Into<Option<ReaderMode>>524     pub fn new<R, M>(inner: R, mode: M) -> Self
525         where R: 'a + Read,
526               M: Into<Option<ReaderMode>>
527     {
528         Self::from_buffered_reader(
529             Box::new(buffered_reader::Generic::new(inner, None)),
530             mode)
531     }
532 
533     /// Creates a `Reader` from an `io::Read`er.
from_reader<R, M>(reader: R, mode: M) -> Self where R: 'a + Read, M: Into<Option<ReaderMode>>534     pub fn from_reader<R, M>(reader: R, mode: M) -> Self
535         where R: 'a + Read,
536               M: Into<Option<ReaderMode>>
537     {
538         Self::from_buffered_reader(
539             Box::new(buffered_reader::Generic::new(reader, None)),
540             mode)
541     }
542 
543     /// Creates a `Reader` from a file.
from_file<P, M>(path: P, mode: M) -> Result<Self> where P: AsRef<Path>, M: Into<Option<ReaderMode>>544     pub fn from_file<P, M>(path: P, mode: M) -> Result<Self>
545         where P: AsRef<Path>,
546               M: Into<Option<ReaderMode>>
547     {
548         Ok(Self::from_buffered_reader(
549             Box::new(buffered_reader::File::open(path)?),
550             mode))
551     }
552 
553     /// Creates a `Reader` from a buffer.
from_bytes<M>(bytes: &'a [u8], mode: M) -> Self where M: Into<Option<ReaderMode>>554     pub fn from_bytes<M>(bytes: &'a [u8], mode: M) -> Self
555         where M: Into<Option<ReaderMode>>
556     {
557         Self::from_buffered_reader(
558             Box::new(buffered_reader::Memory::new(bytes)),
559             mode)
560     }
561 
from_buffered_reader<C: 'a, M>( inner: Box<dyn BufferedReader<C> + 'a>, mode: M) -> Self where M: Into<Option<ReaderMode>>562     pub(crate) fn from_buffered_reader<C: 'a, M>(
563         inner: Box<dyn BufferedReader<C> + 'a>, mode: M) -> Self
564         where M: Into<Option<ReaderMode>>
565     {
566         let mode = mode.into().unwrap_or(Default::default());
567 
568         Reader {
569             source: Box::new(buffered_reader::Generic::new(inner, None)),
570             kind: None,
571             mode,
572             buffer: Vec::<u8>::with_capacity(1024),
573             crc: CRC::new(),
574             expect_crc: None,
575             headers: Vec::new(),
576             initialized: false,
577             finalized: false,
578             prefix_len: 0,
579             prefix_remaining: 0,
580         }
581     }
582 
583     /// Returns the kind of data this reader is for.
584     ///
585     /// Useful if the kind of data is not known in advance.  If the
586     /// header has not been encountered yet (try reading some data
587     /// first!), this function returns None.
kind(&self) -> Option<Kind>588     pub fn kind(&self) -> Option<Kind> {
589         self.kind
590     }
591 
592     /// Returns the armored headers.
593     ///
594     /// The tuples contain a key and a value.
595     ///
596     /// Note: if a key occurs multiple times, then there are multiple
597     /// entries in the vector with the same key; values with the same
598     /// key are *not* combined.
599     ///
600     /// # Examples
601     ///
602     /// ```
603     /// use std::io::{self, Read};
604     /// use sequoia_openpgp as openpgp;
605     /// use openpgp::armor::{Reader, ReaderMode, Kind};
606     ///
607     /// # fn main() -> std::io::Result<()> {
608     /// let data =
609     ///     "-----BEGIN PGP ARMORED FILE-----
610     ///      First: value
611     ///      Header: value
612     ///
613     ///      SGVsbG8gd29ybGQh
614     ///      =s4Gu
615     ///      -----END PGP ARMORED FILE-----";
616     ///
617     /// let mut cursor = io::Cursor::new(&data);
618     /// let mut reader = Reader::new(&mut cursor, ReaderMode::Tolerant(Some(Kind::File)));
619     ///
620     /// let mut content = String::new();
621     /// reader.read_to_string(&mut content)?;
622     /// assert_eq!(reader.headers().unwrap(),
623     ///    &[("First".into(), "value".into()),
624     ///      ("Header".into(), "value".into())]);
625     /// # Ok(())
626     /// # }
627     /// ```
headers(&mut self) -> Result<&[(String, String)]>628     pub fn headers(&mut self) -> Result<&[(String, String)]> {
629         self.initialize()?;
630         Ok(&self.headers[..])
631     }
632 
633     /// Consumes the header if not already done.
initialize(&mut self) -> Result<()>634     fn initialize(&mut self) -> Result<()> {
635         if self.initialized { return Ok(()) }
636 
637         // The range of the first 6 bits of a message is limited.
638         // Save cpu cycles by only considering base64 data that starts
639         // with one of those characters.
640         lazy_static!{
641             static ref START_CHARS : Vec<u8> = {
642                 let mut valid_start = Vec::new();
643                 for &tag in &[ Tag::PKESK, Tag::SKESK,
644                               Tag::OnePassSig, Tag::Signature,
645                               Tag::PublicKey, Tag::SecretKey,
646                               Tag::CompressedData, Tag::Literal ] {
647                     let mut ctb = [ 0u8; 1 ];
648                     let mut o = [ 0u8; 4 ];
649 
650                     CTBNew::new(tag).serialize_into(&mut ctb[..]).unwrap();
651                     base64::encode_config_slice(&ctb[..], base64::STANDARD, &mut o[..]);
652                     valid_start.push(o[0]);
653 
654                     CTBOld::new(tag, BodyLength::Full(0)).unwrap()
655                         .serialize_into(&mut ctb[..]).unwrap();
656                     base64::encode_config_slice(&ctb[..], base64::STANDARD, &mut o[..]);
657                     valid_start.push(o[0]);
658                 }
659 
660                 // The standard start of an ASCII armor header e.g.,
661                 //
662                 //   -----BEGIN PGP MESSAGE-----
663                 valid_start.push('-' as u8);
664 
665                 valid_start.sort();
666                 valid_start.dedup();
667                 valid_start
668             };
669 
670         }
671 
672         // Look for the Armor Header Line, skipping any garbage in the
673         // process.
674         let mut found_blob = false;
675         let start_chars = if self.mode != ReaderMode::VeryTolerant {
676             &[b'-'][..]
677         } else {
678             &START_CHARS[..]
679         };
680 
681         let mut lines = 0;
682         let mut prefix = Vec::new();
683         let n = 'search: loop {
684             if lines > 0 {
685                 // Find the start of the next line.
686                 self.source.drop_through(&[b'\n'], true)?;
687                 crate::vec_truncate(&mut prefix, 0);
688             }
689             lines += 1;
690 
691             // Ignore leading whitespace, etc.
692             while match self.source.data_hard(1)?[0] {
693                 // Skip some whitespace (previously .is_ascii_whitespace())
694                 b' ' | b'\t' | b'\r' | b'\n' => true,
695                 // Also skip common quote characters
696                 b'>' | b'|' | b']' | b'}' => true,
697                 // Do not skip anything else
698                 _ => false,
699             } {
700                 let c = self.source.data(1)?[0];
701                 if c == b'\n' {
702                     // We found a newline while walking whitespace, reset prefix
703                     crate::vec_truncate(&mut prefix, 0);
704                 } else {
705                     prefix.push(self.source.data_hard(1)?[0]);
706                 }
707                 self.source.consume(1);
708             }
709 
710             // Don't bother if the first byte is not plausible.
711             let start = self.source.data_hard(1)?[0];
712             if !start_chars.binary_search(&start).is_ok()
713             {
714                 self.source.consume(1);
715                 continue;
716             }
717 
718             {
719                 let mut input = self.source.data(128)?;
720                 let n = input.len();
721 
722                 if n == 0 {
723                     return Err(
724                         Error::new(ErrorKind::InvalidInput,
725                                    "Reached EOF looking for Armor Header Line"));
726                 }
727                 if n > 128 {
728                     input = &input[..128];
729                 }
730 
731                 if input[0] == '-' as u8 {
732                     // Possible ASCII-armor header.
733                     if let Some(kind) = Kind::detect(&input) {
734                         let mut expected_kind = None;
735                         if let ReaderMode::Tolerant(Some(kind)) = self.mode {
736                             expected_kind = Some(kind);
737                         }
738 
739                         if expected_kind == None {
740                             // Found any!
741                             self.kind = Some(kind);
742                             break 'search kind.header_len();
743                         }
744 
745                         if expected_kind == Some(kind) {
746                             // Found it!
747                             self.kind = Some(kind);
748                             break 'search kind.header_len();
749                         }
750                     }
751                 } else if self.mode == ReaderMode::VeryTolerant {
752                     // The user did not specify what kind of data she
753                     // wants.  We aggressively try to decode any data,
754                     // even if we do not see a valid header.
755                     if is_armored_pgp_blob(input) {
756                         found_blob = true;
757                         break 'search 0;
758                     }
759                 }
760             }
761         };
762         self.source.consume(n);
763 
764         if found_blob {
765             // Skip the rest of the initialization.
766             self.initialized = true;
767             self.prefix_len = prefix.len();
768             self.prefix_remaining = prefix.len();
769             return Ok(());
770         }
771 
772         // We consumed the header above, but not any trailing
773         // whitespace and the trailing new line.  We do that now.
774         // Other data between the header and the new line are not
775         // allowed.  But, instead of failing, we try to recover, by
776         // stopping at the first non-whitespace character.
777         let n = {
778             let line = self.source.read_to('\n' as u8)?;
779             line.iter().position(|&c| {
780                 !c.is_ascii_whitespace()
781             }).unwrap_or(line.len())
782         };
783         self.source.consume(n);
784 
785         let next_prefix = &self.source.data_hard(prefix.len())?[..prefix.len()];
786         if prefix != next_prefix {
787             // If the next line doesn't start with the same prefix, we assume
788             // it was garbage on the front and drop the prefix so long as it
789             // was purely whitespace.  Any non-whitespace remains an error
790             // while searching for the armor header if it's not repeated.
791             if prefix.iter().all(|b| (*b as char).is_ascii_whitespace()) {
792                 crate::vec_truncate(&mut prefix, 0);
793             } else {
794                 // Nope, we have actually failed to read this properly
795                 return Err(
796                     Error::new(ErrorKind::InvalidInput,
797                                "Inconsistent quoting of armored data"));
798             }
799         }
800 
801         // Read the key-value headers.
802         let mut n = 0;
803         let mut lines = 0;
804         loop {
805             // Skip any known prefix on lines.
806             //
807             // IMPORTANT: We need to buffer the prefix so that we can
808             // consume it here.  So at every point in this loop where
809             // the control flow wraps around, we need to make sure
810             // that we buffer the prefix in addition to the line.
811             self.source.consume(prefix.len());
812 
813             self.source.consume(n);
814 
815             // Buffer the next line.
816             let line = self.source.read_to('\n' as u8)?;
817             n = line.len();
818             lines += 1;
819 
820             let line = str::from_utf8(line);
821             // Ignore---don't error out---lines that are not valid UTF8.
822             if line.is_err() {
823                 // Buffer the next line and the prefix that is going
824                 // to be consumed in the next iteration.
825                 let next_prefix =
826                     &self.source.data_hard(n + prefix.len())?[n..n + prefix.len()];
827                 if prefix != next_prefix {
828                     return Err(
829                         Error::new(ErrorKind::InvalidInput,
830                                    "Inconsistent quoting of armored data"));
831                 }
832                 continue;
833             }
834 
835             let line = line.unwrap();
836 
837             // The line almost certainly ends with \n: the only reason
838             // it couldn't is if we encountered EOF.  We need to strip
839             // it.  But, if it ends with \r\n, then we also want to
840             // strip the \r too.
841             let line = if line.ends_with(&"\r\n"[..]) {
842                 // \r\n.
843                 &line[..line.len() - 2]
844             } else if line.ends_with("\n") {
845                 // \n.
846                 &line[..line.len() - 1]
847             } else {
848                 // EOF.
849                 line
850             };
851 
852             /* Process headers.  */
853             let key_value = line.splitn(2, ": ").collect::<Vec<&str>>();
854             if key_value.len() == 1 {
855                 if line.trim_start().len() == 0 {
856                     // Empty line.
857                     break;
858                 } else if lines == 1 {
859                     // This is the first line and we don't have a
860                     // key-value pair.  It seems more likely that
861                     // we're just missing a newline and this invalid
862                     // header is actually part of the body.
863                     n = 0;
864                     break;
865                 }
866             } else {
867                 let key = key_value[0].trim_start();
868                 let value = key_value[1];
869 
870                 self.headers.push((key.into(), value.into()));
871             }
872 
873             // Buffer the next line and the prefix that is going to be
874             // consumed in the next iteration.
875             let next_prefix =
876                 &self.source.data_hard(n + prefix.len())?[n..n + prefix.len()];
877             if prefix != next_prefix {
878                 return Err(
879                     Error::new(ErrorKind::InvalidInput,
880                                "Inconsistent quoting of armored data"));
881             }
882         }
883         self.source.consume(n);
884 
885         self.initialized = true;
886         self.prefix_len = prefix.len();
887         self.prefix_remaining = prefix.len();
888         Ok(())
889     }
890 }
891 
892 // Remove whitespace, etc. from the base64 data.
893 //
894 // This function returns the filtered base64 data (i.e., stripped of
895 // all skipable data like whitespace), and the amount of unfiltered
896 // data that corresponds to.  Thus, if we have the following 7 bytes:
897 //
898 //     ab  cde
899 //     0123456
900 //
901 // This function returns ("abcd", 6), because the 'd' is the last
902 // character in the last complete base64 chunk, and it is at offset 5.
903 //
904 // If 'd' is followed by whitespace, it is undefined whether that
905 // whitespace is included in the count.
906 //
907 // This function only returns full chunks of base64 data.  As a
908 // consequence, if base64_data_max is less than 4, then this will not
909 // return any data.
910 //
911 // This function will stop after it sees base64 padding, and if it
912 // sees invalid base64 data.
base64_filter(mut bytes: Cow<[u8]>, base64_data_max: usize, mut prefix_remaining: usize, prefix_len: usize) -> (Cow<[u8]>, usize, usize)913 fn base64_filter(mut bytes: Cow<[u8]>, base64_data_max: usize,
914                  mut prefix_remaining: usize, prefix_len: usize)
915     -> (Cow<[u8]>, usize, usize)
916 {
917     let mut leading_whitespace = 0;
918 
919     // Round down to the nearest chunk size.
920     let base64_data_max = base64_data_max / 4 * 4;
921 
922     // Number of bytes of base64 data.  Since we update `bytes` in
923     // place, the base64 data is `&bytes[..base64_len]`.
924     let mut base64_len = 0;
925 
926     // Offset of the next byte of unfiltered data to process.
927     let mut unfiltered_offset = 0;
928 
929     // Offset of the last byte of the last ***complete*** base64 chunk
930     // in the unfiltered data.
931     let mut unfiltered_complete_len = 0;
932 
933     // Number of bytes of padding that we've seen so far.
934     let mut padding = 0;
935 
936     while unfiltered_offset < bytes.len()
937         && base64_len < base64_data_max
938         // A valid base64 chunk never starts with padding.
939         && ! (padding > 0 && base64_len % 4 == 0)
940     {
941         // If we have some prefix to skip, skip it.
942         if prefix_remaining > 0 {
943             prefix_remaining -= 1;
944             if unfiltered_offset == 0 {
945                 match bytes {
946                     Cow::Borrowed(s) => {
947                         // We're at the beginning.  Avoid moving
948                         // data by cutting off the start of the
949                         // slice.
950                         bytes = Cow::Borrowed(&s[1..]);
951                         leading_whitespace += 1;
952                         continue;
953                     }
954                     Cow::Owned(_) => (),
955                 }
956             }
957             unfiltered_offset += 1;
958             continue;
959         }
960         match bytes[unfiltered_offset] {
961             // White space.
962             c if c.is_ascii_whitespace() => {
963                 if c == b'\n' {
964                     prefix_remaining = prefix_len;
965                 }
966                 if unfiltered_offset == 0 {
967                     match bytes {
968                         Cow::Borrowed(s) => {
969                             // We're at the beginning.  Avoid moving
970                             // data by cutting off the start of the
971                             // slice.
972                             bytes = Cow::Borrowed(&s[1..]);
973                             leading_whitespace += 1;
974                             continue;
975                         }
976                         Cow::Owned(_) => (),
977                     }
978                 }
979             }
980 
981             // Padding.
982             b'=' => {
983                 if padding == 2 {
984                     // There can never be more than two bytes of
985                     // padding.
986                     break;
987                 }
988                 if base64_len % 4 == 0 {
989                     // Padding can never occur at the start of a
990                     // base64 chunk.
991                     break;
992                 }
993 
994                 if unfiltered_offset != base64_len {
995                     bytes.to_mut()[base64_len] = b'=';
996                 }
997                 base64_len += 1;
998                 if base64_len % 4 == 0 {
999                     unfiltered_complete_len = unfiltered_offset + 1;
1000                 }
1001                 padding += 1;
1002             }
1003 
1004             // The only thing that can occur after padding is
1005             // whitespace or padding.  Those cases were covered above.
1006             _ if padding > 0 => break,
1007 
1008             // Base64 data!
1009             b if is_base64_char(&b) => {
1010                 if unfiltered_offset != base64_len {
1011                     bytes.to_mut()[base64_len] = b;
1012                 }
1013                 base64_len += 1;
1014                 if base64_len % 4 == 0 {
1015                     unfiltered_complete_len = unfiltered_offset + 1;
1016                 }
1017             }
1018 
1019             // Not base64 data.
1020             _ => break,
1021         }
1022 
1023         unfiltered_offset += 1;
1024     }
1025 
1026     let base64_len = base64_len - (base64_len % 4);
1027     unfiltered_complete_len += leading_whitespace;
1028     match bytes {
1029         Cow::Borrowed(s) =>
1030             (Cow::Borrowed(&s[..base64_len]), unfiltered_complete_len,
1031              prefix_remaining),
1032         Cow::Owned(mut v) => {
1033             vec_truncate(&mut v, base64_len);
1034             (Cow::Owned(v), unfiltered_complete_len, prefix_remaining)
1035         }
1036     }
1037 }
1038 
1039 /// Checks whether the given bytes contain armored OpenPGP data.
is_armored_pgp_blob(bytes: &[u8]) -> bool1040 fn is_armored_pgp_blob(bytes: &[u8]) -> bool {
1041     // Get up to 32 bytes of base64 data.  That's 24 bytes of data
1042     // (ignoring padding), which is more than enough to get the first
1043     // packet's header.
1044     let (bytes, _, _) = base64_filter(Cow::Borrowed(bytes), 32, 0, 0);
1045 
1046     match base64::decode_config(&bytes, base64::STANDARD) {
1047         Ok(d) => {
1048             // Don't consider an empty message to be valid.
1049             if d.len() == 0 {
1050                 false
1051             } else {
1052                 let mut br = buffered_reader::Memory::new(&d);
1053                 if let Ok(header) = Header::parse(&mut br) {
1054                     header.ctb().tag().valid_start_of_message()
1055                         && header.valid(false).is_ok()
1056                 } else {
1057                     false
1058                 }
1059             }
1060         },
1061         Err(_err) => false,
1062     }
1063 }
1064 
1065 /// Checks whether the given byte is in the base64 character set.
is_base64_char(b: &u8) -> bool1066 fn is_base64_char(b: &u8) -> bool {
1067     b.is_ascii_alphanumeric() || *b == '+' as u8 || *b == '/' as u8
1068 }
1069 
1070 /// Returns the number of bytes of base64 data are needed to encode
1071 /// `s` bytes of raw data.
base64_size(s: usize) -> usize1072 fn base64_size(s: usize) -> usize {
1073     (s + 3 - 1) / 3 * 4
1074 }
1075 
1076 #[test]
base64_size_test()1077 fn base64_size_test() {
1078     assert_eq!(base64_size(0), 0);
1079     assert_eq!(base64_size(1), 4);
1080     assert_eq!(base64_size(2), 4);
1081     assert_eq!(base64_size(3), 4);
1082     assert_eq!(base64_size(4), 8);
1083     assert_eq!(base64_size(5), 8);
1084     assert_eq!(base64_size(6), 8);
1085     assert_eq!(base64_size(7), 12);
1086 }
1087 
1088 impl<'a> Read for Reader<'a> {
read(&mut self, buf: &mut [u8]) -> Result<usize>1089     fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1090         if ! self.initialized {
1091             self.initialize()?;
1092         }
1093 
1094         if buf.len() == 0 {
1095             // Short-circuit here.  Otherwise, we copy 0 bytes into
1096             // the buffer, which means we decoded 0 bytes, and we
1097             // wrongfully assume that we reached the end of the
1098             // armored block.
1099             return Ok(0);
1100         }
1101 
1102         if self.finalized {
1103             assert_eq!(self.buffer.len(), 0);
1104             return Ok(0);
1105         }
1106 
1107         let (consumed, decoded) = if self.buffer.len() > 0 {
1108             // We have something buffered, use that.
1109 
1110             let amount = cmp::min(buf.len(), self.buffer.len());
1111             buf[..amount].copy_from_slice(&self.buffer[..amount]);
1112             crate::vec_drain_prefix(&mut self.buffer, amount);
1113 
1114             (0, amount)
1115         } else {
1116             // We need to decode some data.  We consider three cases,
1117             // all a function of the size of `buf`:
1118             //
1119             //   - Tiny: if `buf` can hold less than three bytes, then
1120             //     we almost certainly have to double buffer: except
1121             //     at the very end, a base64 chunk consists of 3 bytes
1122             //     of data.
1123             //
1124             //     Note: this happens if the caller does `for c in
1125             //     Reader::new(...).bytes() ...`.  Then it reads one
1126             //     byte of decoded data at a time.
1127             //
1128             //   - Small: if the caller only requests a few bytes at a
1129             //     time, we may as well double buffer to reduce
1130             //     decoding overhead.
1131             //
1132             //   - Large: if `buf` is large, we can decode directly
1133             //     into `buf` and avoid double buffering.  But,
1134             //     because we ignore whitespace, it is hard to
1135             //     determine exactly how much data to read to
1136             //     maximally fill `buf`.
1137 
1138             // We use 64, because ASCII-armor text usually contains 64
1139             // characters of base64 data per line, and this prevents
1140             // turning the borrow into an own.
1141             const THRESHOLD : usize = 64;
1142 
1143             let to_read =
1144                 cmp::max(
1145                     // Tiny or small:
1146                     THRESHOLD + 2,
1147 
1148                     // Large: a heuristic:
1149 
1150                     base64_size(buf.len())
1151                     // Assume about 2 bytes of whitespace (crlf) per
1152                     // 64 character line.
1153                         + 2 * ((buf.len() + 63) / 64));
1154 
1155             let base64data = self.source.data(to_read)?;
1156             let base64data = if base64data.len() > to_read {
1157                 &base64data[..to_read]
1158             } else {
1159                 base64data
1160             };
1161 
1162             let (base64data, consumed, prefix_remaining)
1163                 = base64_filter(Cow::Borrowed(base64data),
1164                                 // base64_size rounds up, but we want
1165                                 // to round down as we have to double
1166                                 // buffer partial chunks.
1167                                 cmp::max(THRESHOLD, buf.len() / 3 * 4),
1168                                 self.prefix_remaining,
1169                                 self.prefix_len);
1170 
1171             // We shouldn't have any partial chunks.
1172             assert_eq!(base64data.len() % 4, 0);
1173 
1174             let decoded = if base64data.len() / 4 * 3 > buf.len() {
1175                 // We need to double buffer.  Decode into a vector.
1176                 // (Note: the computed size *might* be a slight
1177                 // overestimate, because the last base64 chunk may
1178                 // include padding.)
1179                 self.buffer = base64::decode_config(
1180                     &base64data, base64::STANDARD)
1181                     .map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
1182 
1183                 self.crc.update(&self.buffer);
1184 
1185                 let copied = cmp::min(buf.len(), self.buffer.len());
1186                 buf[..copied].copy_from_slice(&self.buffer[..copied]);
1187                 crate::vec_drain_prefix(&mut self.buffer, copied);
1188 
1189                 copied
1190             } else {
1191                 // We can decode directly into the caller-supplied
1192                 // buffer.
1193                 let decoded = base64::decode_config_slice(
1194                     &base64data, base64::STANDARD, buf)
1195                     .map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
1196 
1197                 self.crc.update(&buf[..decoded]);
1198 
1199                 decoded
1200             };
1201 
1202             self.prefix_remaining = prefix_remaining;
1203 
1204             (consumed, decoded)
1205         };
1206 
1207         self.source.consume(consumed);
1208         if decoded == 0 {
1209             self.finalized = true;
1210 
1211             /* Look for CRC.  The CRC is optional.  */
1212             let consumed = {
1213                 // Skip whitespace.
1214                 while self.source.data(1)?.len() > 0
1215                     && self.source.buffer()[0].is_ascii_whitespace()
1216                 {
1217                     self.source.consume(1);
1218                 }
1219 
1220                 let data = self.source.data(5)?;
1221                 let data = if data.len() > 5 {
1222                     &data[..5]
1223                 } else {
1224                     data
1225                 };
1226 
1227                 if data.len() == 5
1228                     && data[0] == '=' as u8
1229                     && data[1..5].iter().all(is_base64_char)
1230                 {
1231                     /* Found.  */
1232                     let crc = match base64::decode_config(
1233                         &data[1..5], base64::STANDARD)
1234                     {
1235                         Ok(d) => d,
1236                         Err(e) => return Err(Error::new(ErrorKind::InvalidInput, e)),
1237                     };
1238 
1239                     assert_eq!(crc.len(), 3);
1240                     let crc =
1241                         (crc[0] as u32) << 16
1242                         | (crc[1] as u32) << 8
1243                         | crc[2] as u32;
1244 
1245                     self.expect_crc = Some(crc);
1246                     5
1247                 } else {
1248                     0
1249                 }
1250             };
1251             self.source.consume(consumed);
1252 
1253             // Skip any expected prefix
1254             self.source.data_consume_hard(self.prefix_len)?;
1255             // Look for a footer.
1256             let consumed = {
1257                 // Skip whitespace.
1258                 while self.source.data(1)?.len() > 0
1259                     && self.source.buffer()[0].is_ascii_whitespace()
1260                 {
1261                     self.source.consume(1);
1262                 }
1263 
1264                 // If we had a header, we require a footer.
1265                 if let Some(kind) = self.kind {
1266                     let footer = kind.end();
1267                     let got = self.source.data(footer.len())?;
1268                     let got = if got.len() > footer.len() {
1269                         &got[..footer.len()]
1270                     } else {
1271                         got
1272                     };
1273                     if footer.as_bytes() != got {
1274                         return Err(Error::new(ErrorKind::InvalidInput,
1275                                               "Invalid ASCII Armor footer."));
1276                     }
1277 
1278                     footer.len()
1279                 } else {
1280                     0
1281                 }
1282             };
1283             self.source.consume(consumed);
1284 
1285             if let Some(crc) = self.expect_crc {
1286                 if self.crc.finalize() != crc {
1287                     return Err(Error::new(ErrorKind::InvalidInput,
1288                                           "Bad CRC sum."));
1289                 }
1290             }
1291         }
1292 
1293         Ok(decoded)
1294     }
1295 }
1296 
1297 const CRC24_INIT: u32 = 0xB704CE;
1298 const CRC24_POLY: u32 = 0x1864CFB;
1299 
1300 struct CRC {
1301     n: u32,
1302 }
1303 
1304 /// Computess the CRC-24, (see [RFC 4880, section 6.1]).
1305 ///
1306 /// [RFC 4880, section 6.1]: https://tools.ietf.org/html/rfc4880#section-6.1
1307 impl CRC {
new() -> Self1308     fn new() -> Self {
1309         CRC { n: CRC24_INIT }
1310     }
1311 
update(&mut self, buf: &[u8]) -> &Self1312     fn update(&mut self, buf: &[u8]) -> &Self {
1313         for octet in buf {
1314             self.n ^= (*octet as u32) << 16;
1315             for _ in 0..8 {
1316                 self.n <<= 1;
1317                 if self.n & 0x1000000 > 0 {
1318                     self.n ^= CRC24_POLY;
1319                 }
1320             }
1321         }
1322         self
1323     }
1324 
finalize(&self) -> u321325     fn finalize(&self) -> u32 {
1326         self.n & 0xFFFFFF
1327     }
1328 }
1329 
1330 #[cfg(test)]
1331 mod test {
1332     use std::io::{Cursor, Read, Write};
1333     use super::CRC;
1334     use super::Kind;
1335     use super::Writer;
1336 
1337     #[test]
crc()1338     fn crc() {
1339         let b = b"foobarbaz";
1340         let crcs = [
1341             0xb704ce,
1342             0x6d2804,
1343             0xa2d10d,
1344             0x4fc255,
1345             0x7aafca,
1346             0xc79c46,
1347             0x7334de,
1348             0x77dc72,
1349             0x000f65,
1350             0xf40d86,
1351         ];
1352 
1353         for len in 0..b.len() + 1 {
1354             assert_eq!(CRC::new().update(&b[..len]).finalize(), crcs[len]);
1355         }
1356     }
1357 
1358     macro_rules! t {
1359         ( $path: expr ) => {
1360             include_bytes!(concat!("../tests/data/armor/", $path))
1361         }
1362     }
1363     macro_rules! vectors {
1364         ( $prefix: expr, $suffix: expr ) => {
1365             &[t!(concat!($prefix, "-0", $suffix)),
1366               t!(concat!($prefix, "-1", $suffix)),
1367               t!(concat!($prefix, "-2", $suffix)),
1368               t!(concat!($prefix, "-3", $suffix)),
1369               t!(concat!($prefix, "-47", $suffix)),
1370               t!(concat!($prefix, "-48", $suffix)),
1371               t!(concat!($prefix, "-49", $suffix)),
1372               t!(concat!($prefix, "-50", $suffix)),
1373               t!(concat!($prefix, "-51", $suffix))]
1374         }
1375     }
1376 
1377     const TEST_BIN: &[&[u8]] = vectors!("test", ".bin");
1378     const TEST_ASC: &[&[u8]] = vectors!("test", ".asc");
1379     const LITERAL_BIN: &[&[u8]] = vectors!("literal", ".bin");
1380     const LITERAL_ASC: &[&[u8]] = vectors!("literal", ".asc");
1381     const LITERAL_NO_HEADER_ASC: &[&[u8]] =
1382         vectors!("literal", "-no-header.asc");
1383     const LITERAL_NO_HEADER_WITH_CHKSUM_ASC: &[&[u8]] =
1384         vectors!("literal", "-no-header-with-chksum.asc");
1385     const LITERAL_NO_NEWLINES_ASC: &[&[u8]] =
1386         vectors!("literal", "-no-newlines.asc");
1387 
1388     #[test]
enarmor()1389     fn enarmor() {
1390         for (bin, asc) in TEST_BIN.iter().zip(TEST_ASC.iter()) {
1391             let mut w =
1392                 Writer::new(Vec::new(), Kind::File).unwrap();
1393             w.write(&[]).unwrap();  // Avoid zero-length optimization.
1394             w.write_all(bin).unwrap();
1395             let buf = w.finalize().unwrap();
1396             assert_eq!(String::from_utf8_lossy(&buf),
1397                        String::from_utf8_lossy(asc));
1398         }
1399     }
1400 
1401     #[test]
enarmor_bytewise()1402     fn enarmor_bytewise() {
1403         for (bin, asc) in TEST_BIN.iter().zip(TEST_ASC.iter()) {
1404             let mut w = Writer::new(Vec::new(), Kind::File).unwrap();
1405             w.write(&[]).unwrap();  // Avoid zero-length optimization.
1406             for b in bin.iter() {
1407                 w.write(&[*b]).unwrap();
1408             }
1409             let buf = w.finalize().unwrap();
1410             assert_eq!(String::from_utf8_lossy(&buf),
1411                        String::from_utf8_lossy(asc));
1412         }
1413     }
1414 
1415     #[test]
drop_writer()1416     fn drop_writer() {
1417         // No ASCII frame shall be emitted if the writer is dropped
1418         // unused.
1419         assert!(Writer::new(Vec::new(), Kind::File).unwrap()
1420                 .finalize().unwrap().is_empty());
1421 
1422         // However, if the user insists, we will encode a zero-byte
1423         // string.
1424         let mut w = Writer::new(Vec::new(), Kind::File).unwrap();
1425         w.write(&[]).unwrap();
1426         let buf = w.finalize().unwrap();
1427         assert_eq!(
1428             &buf[..],
1429             &b"-----BEGIN PGP ARMORED FILE-----\n\
1430                \n\
1431                =twTO\n\
1432                -----END PGP ARMORED FILE-----\n"[..]);
1433     }
1434 
1435     use super::{Reader, ReaderMode};
1436 
1437     #[test]
dearmor_robust()1438     fn dearmor_robust() {
1439         for (i, reference) in LITERAL_BIN.iter().enumerate() {
1440             for test in &[LITERAL_ASC[i],
1441                           LITERAL_NO_HEADER_WITH_CHKSUM_ASC[i],
1442                           LITERAL_NO_HEADER_ASC[i],
1443                           LITERAL_NO_NEWLINES_ASC[i]] {
1444                 let mut r = Reader::new(Cursor::new(test),
1445                                         ReaderMode::VeryTolerant);
1446                 let mut dearmored = Vec::<u8>::new();
1447                 r.read_to_end(&mut dearmored).unwrap();
1448 
1449                 assert_eq!(&dearmored, reference);
1450             }
1451         }
1452     }
1453 
1454     #[test]
dearmor_binary()1455     fn dearmor_binary() {
1456         for bin in TEST_BIN.iter() {
1457             let mut r = Reader::new(
1458                 Cursor::new(bin), ReaderMode::Tolerant(Some(Kind::Message)));
1459             let mut buf = [0; 5];
1460             let e = r.read(&mut buf);
1461             assert!(e.is_err());
1462         }
1463     }
1464 
1465     #[test]
dearmor_wrong_kind()1466     fn dearmor_wrong_kind() {
1467         let mut r = Reader::new(
1468             Cursor::new(&include_bytes!("../tests/data/armor/test-0.asc")[..]),
1469             ReaderMode::Tolerant(Some(Kind::Message)));
1470         let mut buf = [0; 5];
1471         let e = r.read(&mut buf);
1472         assert!(e.is_err());
1473     }
1474 
1475     #[test]
dearmor_wrong_crc()1476     fn dearmor_wrong_crc() {
1477         let mut r = Reader::new(
1478             Cursor::new(
1479                 &include_bytes!("../tests/data/armor/test-0.bad-crc.asc")[..]),
1480             ReaderMode::Tolerant(Some(Kind::File)));
1481         let mut buf = [0; 5];
1482         let e = r.read(&mut buf);
1483         assert!(e.is_err());
1484     }
1485 
1486     #[test]
dearmor_wrong_footer()1487     fn dearmor_wrong_footer() {
1488         let mut r = Reader::new(
1489             Cursor::new(
1490                 &include_bytes!("../tests/data/armor/test-2.bad-footer.asc")[..]
1491             ),
1492             ReaderMode::Tolerant(Some(Kind::File)));
1493         let mut read = 0;
1494         loop {
1495             let mut buf = [0; 5];
1496             match r.read(&mut buf) {
1497                 Ok(0) => panic!("Reached EOF, but expected an error!"),
1498                 Ok(r) => read += r,
1499                 Err(_) => break,
1500             }
1501         }
1502         assert!(read <= 2);
1503     }
1504 
1505     #[test]
dearmor_no_crc()1506     fn dearmor_no_crc() {
1507         let mut r = Reader::new(
1508             Cursor::new(
1509                 &include_bytes!("../tests/data/armor/test-1.no-crc.asc")[..]),
1510             ReaderMode::Tolerant(Some(Kind::File)));
1511         let mut buf = [0; 5];
1512         let e = r.read(&mut buf);
1513         assert!(e.unwrap() == 1 && buf[0] == 0xde);
1514     }
1515 
1516     #[test]
dearmor_with_header()1517     fn dearmor_with_header() {
1518         let mut r = Reader::new(
1519             Cursor::new(
1520                 &include_bytes!("../tests/data/armor/test-3.with-headers.asc")[..]
1521             ),
1522             ReaderMode::Tolerant(Some(Kind::File)));
1523         assert_eq!(r.headers().unwrap(),
1524                    &[("Comment".into(), "Some Header".into()),
1525                      ("Comment".into(), "Another one".into())]);
1526         let mut buf = [0; 5];
1527         let e = r.read(&mut buf);
1528         assert!(e.is_ok());
1529     }
1530 
1531     #[test]
dearmor_any()1532     fn dearmor_any() {
1533         let mut r = Reader::new(
1534             Cursor::new(
1535                 &include_bytes!("../tests/data/armor/test-3.with-headers.asc")[..]
1536             ),
1537             ReaderMode::VeryTolerant);
1538         let mut buf = [0; 5];
1539         let e = r.read(&mut buf);
1540         assert!(r.kind() == Some(Kind::File));
1541         assert!(e.is_ok());
1542     }
1543 
1544     #[test]
dearmor_with_garbage()1545     fn dearmor_with_garbage() {
1546         let armored =
1547             include_bytes!("../tests/data/armor/test-3.with-headers.asc");
1548         // Slap some garbage in front and make sure it still reads ok.
1549         let mut b: Vec<u8> = "Some\ngarbage\nlines\n\t\r  ".into();
1550         b.extend_from_slice(armored);
1551         let mut r = Reader::new(Cursor::new(b), ReaderMode::VeryTolerant);
1552         let mut buf = [0; 5];
1553         let e = r.read(&mut buf);
1554         assert_eq!(r.kind(), Some(Kind::File));
1555         assert!(e.is_ok());
1556 
1557         // Again, but this time add a non-whitespace character in the
1558         // line of the header.
1559         let mut b: Vec<u8> = "Some\ngarbage\nlines\n\t.\r  ".into();
1560         b.extend_from_slice(armored);
1561         let mut r = Reader::new(Cursor::new(b), ReaderMode::VeryTolerant);
1562         let mut buf = [0; 5];
1563         let e = r.read(&mut buf);
1564         assert!(e.is_err());
1565     }
1566 
1567     #[test]
dearmor()1568     fn dearmor() {
1569         for (bin, asc) in TEST_BIN.iter().zip(TEST_ASC.iter()) {
1570             let mut r = Reader::new(
1571                 Cursor::new(asc),
1572                 ReaderMode::Tolerant(Some(Kind::File)));
1573             let mut dearmored = Vec::<u8>::new();
1574             r.read_to_end(&mut dearmored).unwrap();
1575 
1576             assert_eq!(&dearmored, bin);
1577         }
1578     }
1579 
1580     #[test]
dearmor_bytewise()1581     fn dearmor_bytewise() {
1582         for (bin, asc) in TEST_BIN.iter().zip(TEST_ASC.iter()) {
1583             let r = Reader::new(
1584                 Cursor::new(asc),
1585                 ReaderMode::Tolerant(Some(Kind::File)));
1586             let mut dearmored = Vec::<u8>::new();
1587             for c in r.bytes() {
1588                 dearmored.push(c.unwrap());
1589             }
1590 
1591             assert_eq!(&dearmored, bin);
1592         }
1593     }
1594 
1595     #[test]
dearmor_yuge()1596     fn dearmor_yuge() {
1597         let yuge_key = crate::tests::key("yuge-key-so-yuge-the-yugest.asc");
1598         let mut r = Reader::new(Cursor::new(&yuge_key[..]),
1599                                 ReaderMode::VeryTolerant);
1600         let mut dearmored = Vec::<u8>::new();
1601         r.read_to_end(&mut dearmored).unwrap();
1602 
1603         let r = Reader::new(Cursor::new(&yuge_key[..]),
1604                             ReaderMode::VeryTolerant);
1605         let mut dearmored = Vec::<u8>::new();
1606         for c in r.bytes() {
1607             dearmored.push(c.unwrap());
1608         }
1609     }
1610 
1611     #[test]
dearmor_quoted()1612     fn dearmor_quoted() {
1613         let mut r = Reader::new(
1614             Cursor::new(
1615                 &include_bytes!("../tests/data/armor/test-3.with-headers-quoted.asc")[..]
1616             ),
1617             ReaderMode::VeryTolerant);
1618         let mut buf = [0; 5];
1619         let e = r.read(&mut buf);
1620         assert!(r.kind() == Some(Kind::File));
1621         assert!(e.is_ok());
1622     }
1623 
1624     #[test]
dearmor_quoted_a_lot()1625     fn dearmor_quoted_a_lot() {
1626         let mut r = Reader::new(
1627             Cursor::new(
1628                 &include_bytes!("../tests/data/armor/test-3.with-headers-quoted-a-lot.asc")[..]
1629             ),
1630             ReaderMode::VeryTolerant);
1631         let mut buf = [0; 5];
1632         // Loop over the input to ensure we read and verify all the way to the
1633         // end of the input in order to check the checksum and footer validation
1634         loop {
1635             let e = r.read(&mut buf);
1636             assert!(r.kind() == Some(Kind::File));
1637             assert!(e.is_ok());
1638             if e.unwrap() == 0 {
1639                 break;
1640             }
1641         }
1642     }
1643 
1644     #[test]
dearmor_quoted_badly()1645     fn dearmor_quoted_badly() {
1646         let mut r = Reader::new(
1647             Cursor::new(
1648                 &include_bytes!("../tests/data/armor/test-3.with-headers-quoted-badly.asc")[..]
1649             ),
1650             ReaderMode::VeryTolerant);
1651         let mut buf = [0; 5];
1652         let e = r.read(&mut buf);
1653         assert!(e.is_err());
1654     }
1655 
1656     quickcheck! {
1657         fn roundtrip(kind: Kind, payload: Vec<u8>) -> bool {
1658             if payload.is_empty() {
1659                 // Empty payloads do not emit an armor framing unless
1660                 // one does an explicit empty write (and .write_all()
1661                 // does not).
1662                 return true;
1663             }
1664 
1665             let mut w = Writer::new(Vec::new(), kind).unwrap();
1666             w.write_all(&payload).unwrap();
1667             let encoded = w.finalize().unwrap();
1668 
1669             let mut recovered = Vec::new();
1670             Reader::new(Cursor::new(&encoded),
1671                         ReaderMode::Tolerant(Some(kind)))
1672                 .read_to_end(&mut recovered)
1673                 .unwrap();
1674 
1675             let mut recovered_any = Vec::new();
1676             Reader::new(Cursor::new(&encoded), ReaderMode::VeryTolerant)
1677                 .read_to_end(&mut recovered_any)
1678                 .unwrap();
1679 
1680             payload == recovered && payload == recovered_any
1681         }
1682     }
1683 
1684     /// Tests issue #404, zero-sized reads break reader.
1685     ///
1686     /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/404
1687     #[test]
zero_sized_read()1688     fn zero_sized_read() {
1689         let mut r = Reader::from_bytes(crate::tests::file("armor/test-1.asc"),
1690                                        None);
1691         let mut buf = Vec::new();
1692         r.read(&mut buf).unwrap();
1693         r.read(&mut buf).unwrap();
1694     }
1695 
1696     /// Crash in armor parser due to indexing not aligned with UTF-8
1697     /// characters.
1698     ///
1699     /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/515
1700     #[test]
issue_515()1701     fn issue_515() {
1702         let data = [63, 9, 45, 10, 45, 10, 45, 45, 45, 45, 45, 66, 69,
1703                     71, 73, 78, 32, 80, 71, 80, 32, 77, 69, 83, 83,
1704                     65, 71, 69, 45, 45, 45, 45, 45, 45, 152, 152, 152,
1705                     152, 152, 152, 255, 29, 152, 152, 152, 152, 152,
1706                     152, 152, 152, 152, 152, 10, 91, 45, 10, 45, 14,
1707                     0, 36, 0, 0, 30, 122, 4, 2, 204, 152];
1708 
1709         let mut reader = Reader::from_bytes(&data[..], None);
1710         let mut buf = Vec::new();
1711         // `data` is malformed, expect an error.
1712         reader.read_to_end(&mut buf).unwrap_err();
1713     }
1714 
1715     /// Crash in armor parser due to improper use of the buffered
1716     /// reader protocol when consuming quoting prefix.
1717     ///
1718     /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/516
1719     #[test]
issue_516()1720     fn issue_516() {
1721         let data = [
1722             144, 32, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 125, 13, 125,
1723             125, 93, 125, 125, 93, 125, 13, 13, 125, 125, 45, 45, 45,
1724             45, 45, 66, 69, 71, 73, 78, 32, 80, 71, 80, 32, 77, 69,
1725             83, 83, 65, 71, 69, 45, 45, 45, 45, 45, 125, 13, 125,
1726             125, 93, 125, 125, 93, 125, 13, 13, 125, 125, 45, 0, 0,
1727             0, 0, 0, 0, 0, 0, 125, 205, 21, 1, 21, 21, 21, 1, 1, 1,
1728             1, 21, 149, 21, 21, 21, 21, 32, 4, 141, 141, 141, 141,
1729             202, 74, 11, 125, 8, 21, 50, 50, 194, 48, 147, 93, 174,
1730             23, 23, 23, 23, 23, 23, 147, 147, 147, 23, 23, 23, 23,
1731             23, 23, 48, 125, 125, 93, 125, 13, 125, 125, 125, 93,
1732             125, 125, 13, 13, 125, 125, 13, 13, 93, 125, 13, 125, 45,
1733             125, 125, 45, 45, 66, 69, 71, 73, 78, 32, 80, 71, 45, 45,
1734             125, 10, 45, 45, 0, 0, 10, 45, 45, 210, 10, 0, 0, 87, 0,
1735             0, 0, 150, 10, 0, 0, 241, 87, 45, 0, 0, 121, 121, 10, 10,
1736             21, 58];
1737         let mut reader = Reader::from_bytes(&data[..], None);
1738         let mut buf = Vec::new();
1739         // `data` is malformed, expect an error.
1740         reader.read_to_end(&mut buf).unwrap_err();
1741     }
1742 
1743     /// Crash in armor parser due to improper use of the buffered
1744     /// reader protocol when consuming quoting prefix.
1745     ///
1746     /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/517
1747     #[test]
issue_517()1748     fn issue_517() {
1749         let data = [13, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 80,
1750                     71, 80, 32, 77, 69, 83, 83, 65, 71, 69, 45, 45, 45,
1751                     45, 45, 10, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
1752                     13, 13, 139];
1753         let mut reader = Reader::from_bytes(&data[..], None);
1754         let mut buf = Vec::new();
1755         // `data` is malformed, expect an error.
1756         reader.read_to_end(&mut buf).unwrap_err();
1757     }
1758 }
1759