sequoia_openpgp/
armor.rs

1//! ASCII Armor.
2//!
3//! This module deals with ASCII Armored data (see [Section 6 of RFC
4//! 9580]).
5//!
6//!   [Section 6 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#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//! # fn main() -> sequoia_openpgp::Result<()> {
22//! use sequoia_openpgp as openpgp;
23//! use std::fs::File;
24//! use openpgp::armor::{Reader, ReaderMode, Kind};
25//!
26//! let mut file = File::open("somefile.asc")?;
27//! let mut r = Reader::from_reader(&mut file, ReaderMode::Tolerant(Some(Kind::File)));
28//! # Ok(()) }
29//! ```
30
31use buffered_reader::BufferedReader;
32use std::convert::TryFrom;
33use std::fmt;
34use std::io;
35use std::io::{Cursor, Read, Write};
36use std::io::{Result, Error, ErrorKind};
37use std::path::Path;
38use std::cmp;
39use std::str;
40use std::borrow::Cow;
41
42#[cfg(test)]
43use quickcheck::{Arbitrary, Gen};
44
45use base64::Engine;
46use base64::engine::general_purpose::STANDARD as base64std;
47use base64::engine::general_purpose::STANDARD_NO_PAD as base64nopad;
48
49use crate::Profile;
50use crate::packet::prelude::*;
51use crate::packet::header::{BodyLength, CTBNew, CTBOld};
52use crate::parse::Cookie;
53use crate::serialize::MarshalInto;
54use crate::{vec_resize, vec_truncate};
55
56mod base64_utils;
57use base64_utils::*;
58mod crc;
59use crc::Crc;
60
61/// Whether to trace execution by default (on stderr).
62const TRACE: bool = false;
63
64/// The encoded output stream must be represented in lines of no more
65/// than 76 characters each (see [Section 6 of RFC 9580]).  GnuPG
66/// uses 64.
67///
68/// [Section 6 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-6
69pub(crate) const LINE_LENGTH: usize = 64;
70
71const LINE_ENDING: &str = "\n";
72
73/// Specifies the type of data (see [Section 6.2 of RFC 9580]).
74///
75/// [Section 6.2 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-6.2
76#[derive(Copy, Clone, Debug, PartialEq)]
77#[non_exhaustive]
78pub enum Kind {
79    /// A generic OpenPGP message.  (Since its structure hasn't been
80    /// validated, in this crate's terminology, this is just a
81    /// `PacketPile`.)
82    Message,
83    /// A certificate.
84    PublicKey,
85    /// A transferable secret key.
86    SecretKey,
87    /// A detached signature.
88    Signature,
89    /// A generic file.  This is a GnuPG extension.
90    File,
91}
92assert_send_and_sync!(Kind);
93
94#[cfg(test)]
95impl Arbitrary for Kind {
96    fn arbitrary(g: &mut Gen) -> Self {
97        use self::Kind::*;
98        match u8::arbitrary(g) % 5 {
99            0 => Message,
100            1 => PublicKey,
101            2 => SecretKey,
102            3 => Signature,
103            4 => File,
104            _ => unreachable!(),
105        }
106    }
107}
108
109/// Specifies the kind of data as indicated by the label.
110///
111/// This is a non-public variant of `Kind` that is currently only used
112/// for detecting the kind on consumption.
113///
114/// See also <https://gitlab.com/sequoia-pgp/sequoia/-/issues/672>.
115#[derive(Clone, Copy, Debug, PartialEq, Eq)]
116enum Label {
117    /// A generic OpenPGP message.  (Since its structure hasn't been
118    /// validated, in this crate's terminology, this is just a
119    /// `PacketPile`.)
120    Message,
121    /// A certificate.
122    PublicKey,
123    /// A transferable secret key.
124    SecretKey,
125    /// A detached signature.
126    Signature,
127    /// A message using the Cleartext Signature Framework.
128    ///
129    /// See [Section 7 of RFC 9580].
130    ///
131    ///   [Section 7 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-7
132    CleartextSignature,
133    /// A generic file.  This is a GnuPG extension.
134    File,
135}
136assert_send_and_sync!(Label);
137
138impl TryFrom<Label> for Kind {
139    type Error = crate::Error;
140    fn try_from(l: Label) -> std::result::Result<Self, Self::Error> {
141        match l {
142            Label::Message => Ok(Kind::Message),
143            Label::PublicKey => Ok(Kind::PublicKey),
144            Label::SecretKey => Ok(Kind::SecretKey),
145            Label::Signature => Ok(Kind::Signature),
146            Label::File => Ok(Kind::File),
147            Label::CleartextSignature => Err(crate::Error::InvalidOperation(
148                "armor::Kind cannot express cleartext signatures".into())),
149        }
150    }
151}
152
153impl Label {
154    /// Detects the header returning the kind and length of the
155    /// header.
156    fn detect_header(blurb: &[u8]) -> Option<(Self, usize)> {
157        let (leading_dashes, rest) = dash_prefix(blurb);
158
159        // Skip over "BEGIN PGP "
160        if ! rest.starts_with(b"BEGIN PGP ") {
161            return None;
162        }
163        let rest = &rest[b"BEGIN PGP ".len()..];
164
165        // Detect kind.
166        let kind = if rest.starts_with(b"MESSAGE") {
167            Label::Message
168        } else if rest.starts_with(b"PUBLIC KEY BLOCK") {
169            Label::PublicKey
170        } else if rest.starts_with(b"PRIVATE KEY BLOCK") {
171            Label::SecretKey
172        } else if rest.starts_with(b"SIGNATURE") {
173            Label::Signature
174        } else if rest.starts_with(b"SIGNED MESSAGE") {
175            Label::CleartextSignature
176        } else if rest.starts_with(b"ARMORED FILE") {
177            Label::File
178        } else {
179            return None;
180        };
181
182        let (trailing_dashes, _) = dash_prefix(&rest[kind.blurb().len()..]);
183        Some((kind,
184              leading_dashes.len()
185              + b"BEGIN PGP ".len() + kind.blurb().len()
186              + trailing_dashes.len()))
187    }
188
189    fn blurb(&self) -> &str {
190        match self {
191            Label::Message => "MESSAGE",
192            Label::PublicKey => "PUBLIC KEY BLOCK",
193            Label::SecretKey => "PRIVATE KEY BLOCK",
194            Label::Signature => "SIGNATURE",
195            Label::CleartextSignature => "SIGNED MESSAGE",
196            Label::File => "ARMORED FILE",
197        }
198    }
199
200}
201
202impl Kind {
203    /// Detects the footer returning length of the footer.
204    fn detect_footer(&self, blurb: &[u8]) -> Option<usize> {
205        tracer!(TRACE, "armor::Kind::detect_footer");
206        t!("Looking for footer in {:?}", String::from_utf8_lossy(blurb));
207        let (leading_dashes, rest) = dash_prefix(blurb);
208
209        // Skip over "END PGP "
210        if ! rest.starts_with(b"END PGP ") {
211            return None;
212        }
213        let rest = &rest[b"END PGP ".len()..];
214
215        let ident = self.blurb().as_bytes();
216        if ! rest.starts_with(ident) {
217            return None;
218        }
219
220        let (trailing_dashes, _) = dash_prefix(&rest[ident.len()..]);
221        Some(leading_dashes.len()
222             + b"END PGP ".len() + ident.len()
223             + trailing_dashes.len())
224    }
225
226    fn blurb(&self) -> &str {
227        match self {
228            Kind::Message => "MESSAGE",
229            Kind::PublicKey => "PUBLIC KEY BLOCK",
230            Kind::SecretKey => "PRIVATE KEY BLOCK",
231            Kind::Signature => "SIGNATURE",
232            Kind::File => "ARMORED FILE",
233        }
234    }
235
236    fn begin(&self) -> String {
237        format!("-----BEGIN PGP {}-----", self.blurb())
238    }
239
240    fn end(&self) -> String {
241        format!("-----END PGP {}-----", self.blurb())
242    }
243}
244
245/// A filter that applies ASCII Armor to the data written to it.
246pub struct Writer<W: Write> {
247    sink: W,
248    profile: Option<Profile>,
249    kind: Kind,
250    stash: Vec<u8>,
251    column: usize,
252    crc: Crc,
253    header: Vec<u8>,
254    dirty: bool,
255    scratch: Vec<u8>,
256}
257assert_send_and_sync!(Writer<W> where W: Write);
258
259impl<W: Write> Writer<W> {
260    /// Constructs a new filter for the given type of data.
261    ///
262    /// # Examples
263    ///
264    /// ```
265    /// use std::io::{Read, Write, Cursor};
266    /// use sequoia_openpgp as openpgp;
267    /// use openpgp::armor::{Writer, Kind};
268    ///
269    /// # fn main() -> std::io::Result<()> {
270    /// let mut writer = Writer::new(Vec::new(), Kind::File)?;
271    /// writer.write_all(b"Hello world!")?;
272    /// let buffer = writer.finalize()?;
273    /// assert_eq!(
274    ///     String::from_utf8_lossy(&buffer),
275    ///     "-----BEGIN PGP ARMORED FILE-----
276    ///
277    /// SGVsbG8gd29ybGQh
278    /// =s4Gu
279    /// -----END PGP ARMORED FILE-----
280    /// ");
281    /// # Ok(())
282    /// # }
283    /// ```
284    pub fn new(inner: W, kind: Kind) -> Result<Self> {
285        Self::with_headers(inner, kind, Option::<(&str, &str)>::None)
286    }
287
288    /// Constructs a new filter for the given type of data.
289    ///
290    /// # Examples
291    ///
292    /// ```
293    /// use std::io::{Read, Write, Cursor};
294    /// use sequoia_openpgp as openpgp;
295    /// use openpgp::armor::{Writer, Kind};
296    ///
297    /// # fn main() -> std::io::Result<()> {
298    /// let mut writer = Writer::with_headers(Vec::new(), Kind::File,
299    ///     vec![("Key", "Value")])?;
300    /// writer.write_all(b"Hello world!")?;
301    /// let buffer = writer.finalize()?;
302    /// assert_eq!(
303    ///     String::from_utf8_lossy(&buffer),
304    ///     "-----BEGIN PGP ARMORED FILE-----
305    /// Key: Value
306    ///
307    /// SGVsbG8gd29ybGQh
308    /// =s4Gu
309    /// -----END PGP ARMORED FILE-----
310    /// ");
311    /// # Ok(())
312    /// # }
313    /// ```
314    pub fn with_headers<I, K, V>(inner: W, kind: Kind, headers: I)
315                                 -> Result<Self>
316        where I: IntoIterator<Item = (K, V)>,
317              K: AsRef<str>,
318              V: AsRef<str>,
319    {
320        let mut w = Writer {
321            sink: inner,
322            profile: None,
323            kind,
324            stash: Vec::<u8>::with_capacity(2),
325            column: 0,
326            crc: Crc::new(),
327            header: Vec::with_capacity(128),
328            dirty: false,
329            scratch: vec![0; 4096],
330        };
331
332        {
333            let mut cur = Cursor::new(&mut w.header);
334            write!(&mut cur, "{}{}", kind.begin(), LINE_ENDING)?;
335
336            for h in headers {
337                write!(&mut cur, "{}: {}{}", h.0.as_ref(), h.1.as_ref(),
338                       LINE_ENDING)?;
339            }
340
341            // A blank line separates the headers from the body.
342            write!(&mut cur, "{}", LINE_ENDING)?;
343        }
344
345        Ok(w)
346    }
347
348    /// Sets the version of OpenPGP to generate ASCII Armor for.
349    ///
350    /// This function can only be called once.  Calling it repeatedly
351    /// will return an error.
352    ///
353    /// # Examples
354    ///
355    /// ```
356    /// use std::io::{Read, Write, Cursor};
357    /// use sequoia_openpgp as openpgp;
358    /// use openpgp::armor::{Writer, Kind};
359    ///
360    /// # fn main() -> std::io::Result<()> {
361    /// let mut writer = Writer::new(Vec::new(), Kind::File)?;
362    ///
363    /// writer.set_profile(openpgp::Profile::RFC9580)?;
364    /// writer.set_profile(openpgp::Profile::RFC9580).unwrap_err();
365    /// writer.set_profile(openpgp::Profile::RFC4880).unwrap_err();
366    ///
367    /// writer.write_all(b"Hello world!")?;
368    /// let buffer = writer.finalize()?;
369    /// assert_eq!(
370    ///     String::from_utf8_lossy(&buffer),
371    ///     "-----BEGIN PGP ARMORED FILE-----
372    ///
373    /// SGVsbG8gd29ybGQh
374    /// -----END PGP ARMORED FILE-----
375    /// ");
376    /// # Ok(())
377    /// # }
378    /// ```
379    pub fn set_profile(&mut self, profile: Profile) -> Result<()> {
380        if self.profile.is_some() {
381            return Err(io::Error::new(
382                io::ErrorKind::Other,
383                "profile already selected"));
384        }
385
386        self.profile = Some(profile);
387        Ok(())
388    }
389
390    /// Returns a reference to the inner writer.
391    pub fn get_ref(&self) -> &W {
392        &self.sink
393    }
394
395    /// Returns a mutable reference to the inner writer.
396    pub fn get_mut(&mut self) -> &mut W {
397        &mut self.sink
398    }
399
400    fn finalize_headers(&mut self) -> Result<()> {
401        if ! self.dirty {
402            self.dirty = true;
403            self.sink.write_all(&self.header)?;
404            // Release memory.
405            crate::vec_truncate(&mut self.header, 0);
406            self.header.shrink_to_fit();
407        }
408        Ok(())
409    }
410
411    /// Writes the footer.
412    ///
413    /// This function needs to be called explicitly before the writer is dropped.
414    pub fn finalize(mut self) -> Result<W> {
415        if ! self.dirty {
416            // No data was written to us, don't emit anything.
417            return Ok(self.sink);
418        }
419        self.finalize_armor()?;
420        Ok(self.sink)
421    }
422
423    /// Writes the footer.
424    fn finalize_armor(&mut self) -> Result<()> {
425        if ! self.dirty {
426            // No data was written to us, don't emit anything.
427            return Ok(());
428        }
429        self.finalize_headers()?;
430
431        // Write any stashed bytes and pad.
432        if !self.stash.is_empty() {
433            self.sink.write_all(base64std.encode(&self.stash).as_bytes())?;
434            self.column += 4;
435        }
436
437        // Inserts a line break if necessary.
438        //
439        // Unfortunately, we cannot use
440        //self.linebreak()?;
441        //
442        // Therefore, we inline it here.  This is a bit sad.
443        assert!(self.column <= LINE_LENGTH);
444        if self.column == LINE_LENGTH {
445            write!(self.sink, "{}", LINE_ENDING)?;
446            self.column = 0;
447        }
448
449        if self.column > 0 {
450            write!(self.sink, "{}", LINE_ENDING)?;
451        }
452
453        match self.profile {
454            None | Some(Profile::RFC4880) => {
455                // 24-bit CRC
456                let crc = self.crc.finalize();
457                let bytes = &crc.to_be_bytes()[1..4];
458
459                // Emit the CRC line.
460                write!(self.sink, "={}{}",
461                       base64nopad.encode(&bytes), LINE_ENDING)?;
462            },
463
464            Some(Profile::RFC9580) => (),
465        }
466
467        // Finally, emit the footer.
468        write!(self.sink, "{}{}", self.kind.end(), LINE_ENDING)?;
469
470        self.dirty = false;
471        crate::vec_truncate(&mut self.scratch, 0);
472        Ok(())
473    }
474
475    /// Inserts a line break if necessary.
476    fn linebreak(&mut self) -> Result<()> {
477        assert!(self.column <= LINE_LENGTH);
478        if self.column == LINE_LENGTH {
479            write!(self.sink, "{}", LINE_ENDING)?;
480            self.column = 0;
481        }
482        Ok(())
483    }
484}
485
486impl<W: Write> Write for Writer<W> {
487    fn write(&mut self, buf: &[u8]) -> Result<usize> {
488        self.finalize_headers()?;
489        assert!(self.dirty);
490
491        match self.profile {
492            None | Some(Profile::RFC4880) => {
493                // Update CRC on the unencoded data.
494                self.crc.update(buf);
495            },
496
497            Some(Profile::RFC9580) => (),
498        }
499
500        let mut input = buf;
501        let mut written = 0;
502
503        // First of all, if there are stashed bytes, fill the stash
504        // and encode it.  If writing out the stash fails below, we
505        // might end up with a stash of size 3.
506        assert!(self.stash.len() <= 3);
507        if !self.stash.is_empty() {
508            let missing = 3 - self.stash.len();
509            let n = missing.min(input.len());
510            self.stash.extend_from_slice(&input[..n]);
511            input = &input[n..];
512            written += n;
513            if input.is_empty() {
514                // We exhausted the input.  Return now, any stashed
515                // bytes are encoded when finalizing the writer.
516                return Ok(written);
517            }
518            assert_eq!(self.stash.len(), 3);
519
520            // If this fails for some reason, and the caller retries
521            // the write, we might end up with a stash of size 3.
522            self.sink
523                .write_all(base64nopad.encode(&self.stash).as_bytes())?;
524            self.column += 4;
525            self.linebreak()?;
526            crate::vec_truncate(&mut self.stash, 0);
527        }
528
529        // Encode all whole blocks of 3 bytes.
530        let n_blocks = input.len() / 3;
531        let input_bytes = n_blocks * 3;
532        if input_bytes > 0 {
533            // Encrypt whole blocks.
534            let encoded_bytes = n_blocks * 4;
535            if self.scratch.len() < encoded_bytes {
536                vec_resize(&mut self.scratch, encoded_bytes);
537            }
538
539            written += input_bytes;
540            base64nopad.encode_slice(&input[..input_bytes],
541                                  &mut self.scratch[..encoded_bytes])
542                .expect("buffer correctly sized");
543
544            let mut n = 0;
545            while ! self.scratch[n..encoded_bytes].is_empty() {
546                let m = self.scratch[n..encoded_bytes].len()
547                    .min(LINE_LENGTH - self.column);
548                self.sink.write_all(&self.scratch[n..n + m])?;
549                n += m;
550                self.column += m;
551                self.linebreak()?;
552            }
553        }
554
555        // Stash rest for later.
556        input = &input[input_bytes..];
557        assert!(input.is_empty() || self.stash.is_empty());
558        self.stash.extend_from_slice(input);
559        written += input.len();
560
561        assert_eq!(written, buf.len());
562        Ok(written)
563    }
564
565    fn flush(&mut self) -> Result<()> {
566        self.sink.flush()
567    }
568}
569
570/// How an ArmorReader should act.
571#[derive(Debug, Clone, Copy, PartialEq)]
572#[non_exhaustive]
573pub enum ReaderMode {
574    /// Makes the armor reader tolerant of simple errors.
575    ///
576    /// The armor reader will be tolerant of common formatting errors,
577    /// such as incorrect line folding, but the armor header line
578    /// (e.g., `----- BEGIN PGP MESSAGE -----`) and the footer must be
579    /// intact.
580    ///
581    /// If a Kind is specified, then only ASCII Armor blocks with the
582    /// appropriate header are recognized.
583    ///
584    /// This mode is appropriate when reading from a file.
585    Tolerant(Option<Kind>),
586
587    /// Makes the armor reader very tolerant of errors.
588    ///
589    /// Unlike in `Tolerant` mode, in this mode, the armor reader
590    /// doesn't require an armor header line.  Instead, it examines
591    /// chunks that look like valid base64 data, and attempts to parse
592    /// them.
593    ///
594    /// Although this mode looks for OpenPGP fingerprints before
595    /// invoking the full parser, due to the number of false
596    /// positives, this mode of operation is CPU intense, particularly
597    /// on large text files.  It is primarily appropriate when reading
598    /// text that the user cut and pasted into a text area.
599    VeryTolerant,
600}
601assert_send_and_sync!(ReaderMode);
602
603/// A filter that strips ASCII Armor from a stream of data.
604#[derive(Debug)]
605pub struct Reader<'a> {
606    // The following fields are the state of an embedded
607    // buffered_reader::Generic.  We need to be able to access the
608    // cookie in Self::initialize, therefore using
609    // buffered_reader::Generic as we used to is no longer an option.
610    //
611    // XXX: Directly implement the BufferedReader protocol.  This may
612    // actually simplify the code and reduce the required buffering.
613
614    buffer: Option<Vec<u8>>,
615    /// Currently unused buffer, a cache.
616    unused_buffer: Option<Vec<u8>>,
617    // The next byte to read in the buffer.
618    cursor: usize,
619    // The preferred chunk size.  This is just a hint.
620    preferred_chunk_size: usize,
621    // The wrapped reader.
622    source: Box<dyn BufferedReader<Cookie> + 'a>,
623    // Stashed error, if any.
624    error: Option<Error>,
625    /// Whether we hit EOF on the underlying reader.
626    eof: bool,
627    // The user settable cookie.
628    cookie: Cookie,
629    // End fields of the embedded generic reader.
630
631    kind: Option<Kind>,
632    mode: ReaderMode,
633    decode_buffer: Vec<u8>,
634    initialized: bool,
635    headers: Vec<(String, String)>,
636    finalized: bool,
637    prefix: Vec<u8>,
638    prefix_remaining: usize,
639
640    /// Controls the transformation of messages using the Cleartext
641    /// Signature Framework into inline signed messages.
642    enable_csft: bool,
643
644    /// State for the CSF transformer.
645    csft: Option<CSFTransformer>,
646}
647assert_send_and_sync!(Reader<'_>);
648
649// The default buffer size.
650const DEFAULT_BUF_SIZE: usize = 32 * 1024;
651
652impl<'a> fmt::Display for Reader<'a> {
653    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
654        write!(f, "armor::Reader")
655    }
656}
657
658impl Default for ReaderMode {
659    fn default() -> Self {
660        ReaderMode::Tolerant(None)
661    }
662}
663
664/// State for transforming a message using the Cleartext Signature
665/// Framework into an inline signed message.
666#[derive(Clone, Copy, Debug, PartialEq, Eq)]
667enum CSFTransformer {
668    Transform,
669    Read,
670}
671
672impl Default for CSFTransformer {
673    fn default() -> Self {
674        CSFTransformer::Transform
675    }
676}
677
678impl<'a> Reader<'a> {
679    /// Constructs a new `Reader` from the given `BufferedReader`.
680    pub fn from_buffered_reader<R, M>(reader: R, mode: M) -> Result<Self>
681    where
682        R: BufferedReader<Cookie> + 'a,
683        M: Into<Option<ReaderMode>>,
684    {
685        Ok(Self::from_cookie_reader(reader.into_boxed(), mode, Default::default()))
686    }
687
688    /// Constructs a new `Reader` from the given `io::Read`er.
689    ///
690    /// [ASCII Armor], designed to protect OpenPGP data in transit,
691    /// has been a source of problems if the armor structure is
692    /// damaged.  For example, copying data manually from one program
693    /// to another might introduce or drop newlines.
694    ///
695    /// By default, the reader operates in tolerant mode.  It will
696    /// ignore common formatting errors but the header and footer
697    /// lines must be intact.
698    ///
699    /// To select stricter mode, specify the kind argument for
700    /// tolerant mode.  In this mode only ASCII Armor blocks with the
701    /// appropriate header are recognized.
702    ///
703    /// There is also very tolerant mode that is appropriate when
704    /// reading text that the user cut and pasted into a text area.
705    /// This mode of operation is CPU intense, particularly on large
706    /// text files.
707    ///
708    ///   [ASCII Armor]: https://www.rfc-editor.org/rfc/rfc9580.html#section-6.2
709    ///
710    /// # Examples
711    ///
712    /// ```
713    /// use std::io::{self, Read};
714    /// use sequoia_openpgp as openpgp;
715    /// use openpgp::Message;
716    /// use openpgp::armor::{Reader, ReaderMode};
717    /// use openpgp::parse::Parse;
718    ///
719    /// # fn main() -> openpgp::Result<()> {
720    /// let data = "yxJiAAAAAABIZWxsbyB3b3JsZCE="; // base64 over literal data packet
721    ///
722    /// let mut cursor = io::Cursor::new(&data);
723    /// let mut reader = Reader::from_reader(&mut cursor, ReaderMode::VeryTolerant);
724    ///
725    /// let mut buf = Vec::new();
726    /// reader.read_to_end(&mut buf)?;
727    ///
728    /// let message = Message::from_bytes(&buf)?;
729    /// assert_eq!(message.body().unwrap().body(),
730    ///            b"Hello world!");
731    /// # Ok(())
732    /// # }
733    /// ```
734    ///
735    /// Or, in strict mode:
736    ///
737    /// ```
738    /// use std::io::{self, Result, Read};
739    /// use sequoia_openpgp as openpgp;
740    /// use openpgp::armor::{Reader, ReaderMode, Kind};
741    ///
742    /// # fn main() -> Result<()> {
743    /// let data =
744    ///     "-----BEGIN PGP ARMORED FILE-----
745    ///
746    ///      SGVsbG8gd29ybGQh
747    ///      =s4Gu
748    ///      -----END PGP ARMORED FILE-----";
749    ///
750    /// let mut cursor = io::Cursor::new(&data);
751    /// let mut reader = Reader::from_reader(&mut cursor, ReaderMode::Tolerant(Some(Kind::File)));
752    ///
753    /// let mut content = String::new();
754    /// reader.read_to_string(&mut content)?;
755    /// assert_eq!(content, "Hello world!");
756    /// assert_eq!(reader.kind(), Some(Kind::File));
757    /// # Ok(())
758    /// # }
759    /// ```
760    pub fn from_reader<R, M>(reader: R, mode: M) -> Self
761        where R: 'a + Read + Send + Sync,
762              M: Into<Option<ReaderMode>>
763    {
764        Self::from_cookie_reader(
765            Box::new(buffered_reader::Generic::with_cookie(reader, None,
766                                                           Default::default())),
767            mode, Default::default())
768    }
769
770    /// Creates a `Reader` from a file.
771    pub fn from_file<P, M>(path: P, mode: M) -> Result<Self>
772        where P: AsRef<Path>,
773              M: Into<Option<ReaderMode>>
774    {
775        Ok(Self::from_cookie_reader(
776            Box::new(buffered_reader::File::with_cookie(path,
777                                                        Default::default())?),
778            mode, Default::default()))
779    }
780
781    /// Creates a `Reader` from a buffer.
782    pub fn from_bytes<M>(bytes: &'a [u8], mode: M) -> Self
783        where M: Into<Option<ReaderMode>>
784    {
785        Self::from_cookie_reader(
786            Box::new(buffered_reader::Memory::with_cookie(bytes,
787                                                          Default::default())),
788            mode, Default::default())
789    }
790
791    pub(crate) fn from_cookie_reader<M>(
792        inner: Box<dyn BufferedReader<Cookie> + 'a>, mode: M, cookie: Cookie)
793        -> Self
794        where M: Into<Option<ReaderMode>>
795    {
796        Self::from_cookie_reader_csft(inner, mode.into(), cookie, false)
797    }
798
799    pub(crate) fn from_cookie_reader_csft(
800        inner: Box<dyn BufferedReader<Cookie> + 'a>,
801        mode: Option<ReaderMode>,
802        cookie: Cookie,
803        enable_csft: bool,
804    )
805        -> Self
806    {
807        let mode = mode.unwrap_or_default();
808
809        Reader {
810            // The embedded generic reader's fields.
811            buffer: None,
812            unused_buffer: None,
813            cursor: 0,
814            preferred_chunk_size: DEFAULT_BUF_SIZE,
815            source: inner,
816            error: None,
817            eof: false,
818            cookie,
819            // End of the embedded generic reader's fields.
820
821            kind: None,
822            mode,
823            decode_buffer: Vec::<u8>::with_capacity(1024),
824            headers: Vec::new(),
825            initialized: false,
826            finalized: false,
827            prefix: Vec::with_capacity(0),
828            prefix_remaining: 0,
829            enable_csft,
830            csft: None,
831        }
832    }
833
834    /// Returns the kind of data this reader is for.
835    ///
836    /// Useful if the kind of data is not known in advance.  If the
837    /// header has not been encountered yet (try reading some data
838    /// first!), this function returns None.
839    pub fn kind(&self) -> Option<Kind> {
840        self.kind
841    }
842
843    /// Returns the armored headers.
844    ///
845    /// The tuples contain a key and a value.
846    ///
847    /// Note: if a key occurs multiple times, then there are multiple
848    /// entries in the vector with the same key; values with the same
849    /// key are *not* combined.
850    ///
851    /// # Examples
852    ///
853    /// ```
854    /// use std::io::{self, Read};
855    /// use sequoia_openpgp as openpgp;
856    /// use openpgp::armor::{Reader, ReaderMode, Kind};
857    ///
858    /// # fn main() -> std::io::Result<()> {
859    /// let data =
860    ///     "-----BEGIN PGP ARMORED FILE-----
861    ///      First: value
862    ///      Header: value
863    ///
864    ///      SGVsbG8gd29ybGQh
865    ///      =s4Gu
866    ///      -----END PGP ARMORED FILE-----";
867    ///
868    /// let mut cursor = io::Cursor::new(&data);
869    /// let mut reader = Reader::from_reader(&mut cursor, ReaderMode::Tolerant(Some(Kind::File)));
870    ///
871    /// let mut content = String::new();
872    /// reader.read_to_string(&mut content)?;
873    /// assert_eq!(reader.headers()?,
874    ///    &[("First".into(), "value".into()),
875    ///      ("Header".into(), "value".into())]);
876    /// # Ok(())
877    /// # }
878    /// ```
879    pub fn headers(&mut self) -> Result<&[(String, String)]> {
880        self.initialize()?;
881        Ok(&self.headers[..])
882    }
883}
884
885impl<'a> Reader<'a> {
886    /// Consumes the header if not already done.
887    fn initialize(&mut self) -> Result<()> {
888        tracer!(TRACE, "armor::Reader::initialize");
889        t!("self.initialized is {:?}", self.initialized);
890        if self.initialized { return Ok(()) }
891
892        // The range of the first 6 bits of a message is limited.
893        // Save cpu cycles by only considering base64 data that starts
894        // with one of those characters.
895        fn start_chars_very_tolerant() -> &'static [u8] {
896            use std::sync::OnceLock;
897
898            static START_CHARS_VERY_TOLERANT: OnceLock<Vec<u8>>
899                = OnceLock::new();
900
901            START_CHARS_VERY_TOLERANT.get_or_init(|| {
902                let mut valid_start = Vec::new();
903                for &tag in &[ Tag::PKESK, Tag::SKESK,
904                              Tag::OnePassSig, Tag::Signature,
905                              Tag::PublicKey, Tag::SecretKey,
906                              Tag::CompressedData, Tag::Literal,
907                              Tag::Marker,
908                ] {
909                    let mut ctb = [ 0u8; 1 ];
910                    let mut o = [ 0u8; 4 ];
911
912                    CTBNew::new(tag).serialize_into(&mut ctb[..]).unwrap();
913                    base64std.encode_slice(&ctb[..], &mut o[..])
914                        .expect("buffer correctly sized");
915                    valid_start.push(o[0]);
916
917                    CTBOld::new(tag, BodyLength::Full(0)).unwrap()
918                        .serialize_into(&mut ctb[..]).unwrap();
919                    base64std.encode_slice(&ctb[..], &mut o[..])
920                        .expect("buffer correctly sized");
921                    valid_start.push(o[0]);
922                }
923
924                // Add all first bytes of Unicode characters from the
925                // "Dash Punctuation" category.
926                let mut b = [0; 4]; // Enough to hold any UTF-8 character.
927                for d in dashes() {
928                    d.encode_utf8(&mut b);
929                    valid_start.push(b[0]);
930                }
931
932                // If there are no dashes at all, match on the BEGIN.
933                valid_start.push(b'B');
934
935                valid_start.sort_unstable();
936                valid_start.dedup();
937                valid_start
938            })
939        }
940
941        fn start_chars_tolerant() -> &'static [u8] {
942            use std::sync::OnceLock;
943
944            static START_CHARS_TOLERANT: OnceLock<Vec<u8>>
945                = OnceLock::new();
946
947            START_CHARS_TOLERANT.get_or_init(|| {
948                let mut valid_start = Vec::new();
949                // Add all first bytes of Unicode characters from the
950                // "Dash Punctuation" category.
951                let mut b = [0; 4]; // Enough to hold any UTF-8 character.
952                for d in dashes() {
953                    d.encode_utf8(&mut b);
954                    valid_start.push(b[0]);
955                }
956
957                // If there are no dashes at all, match on the BEGIN.
958                valid_start.push(b'B');
959
960                valid_start.sort_unstable();
961                valid_start.dedup();
962                valid_start
963            })
964        }
965
966        // Look for the Armor Header Line, skipping any garbage in the
967        // process.
968        let mut found_blob = false;
969        let start_chars = if self.mode != ReaderMode::VeryTolerant {
970            start_chars_tolerant()
971        } else {
972            start_chars_very_tolerant()
973        };
974
975        let mut lines = 0;
976        let mut prefix = Vec::new();
977        let n = 'search: loop {
978            if lines > 0 {
979                // Find the start of the next line.
980                self.source.drop_through(&[b'\n'], true)?;
981                crate::vec_truncate(&mut prefix, 0);
982            }
983            lines += 1;
984
985            // Ignore leading whitespace, etc.
986            while matches!(self.source.data_hard(1)?[0],
987                // Skip some whitespace (previously .is_ascii_whitespace())
988                b' ' | b'\t' | b'\r' | b'\n' |
989                // Also skip common quote characters
990                b'>' | b'|' | b']' | b'}' )
991            {
992                let c = self.source.data(1)?[0];
993                if c == b'\n' {
994                    // We found a newline while walking whitespace, reset prefix
995                    crate::vec_truncate(&mut prefix, 0);
996                } else {
997                    prefix.push(self.source.data_hard(1)?[0]);
998                }
999                self.source.consume(1);
1000            }
1001
1002            // Don't bother if the first byte is not plausible.
1003            let start = self.source.data_hard(1)?[0];
1004            if !start_chars.binary_search(&start).is_ok()
1005            {
1006                self.source.consume(1);
1007                continue;
1008            }
1009
1010            {
1011                let mut input = self.source.data(128)?;
1012                let n = input.len();
1013
1014                if n == 0 {
1015                    return Err(
1016                        Error::new(ErrorKind::InvalidInput,
1017                                   "Reached EOF looking for Armor Header Line"));
1018                }
1019                if n > 128 {
1020                    input = &input[..128];
1021                }
1022
1023                // Possible ASCII-armor header.
1024                if let Some((label, len)) = Label::detect_header(input) {
1025                    t!("Found the label {:?}", label);
1026                    if label == Label::CleartextSignature && ! self.enable_csft
1027                    {
1028                        // We found a message using the Cleartext
1029                        // Signature Framework, but the CSF
1030                        // transformation is not enabled.  Continue
1031                        // searching until we find the bare signature.
1032                        continue 'search;
1033                    }
1034
1035                    if label == Label::CleartextSignature && self.enable_csft
1036                    {
1037                        // Initialize the transformer.
1038                        self.csft = Some(CSFTransformer::default());
1039
1040                        // Signal to the parser stack that the CSF
1041                        // transformation is happening.  This will be
1042                        // used by the HashedReader (specifically, in
1043                        // Cookie::processing_csf_message and
1044                        // Cookie::hash_update) to select the correct
1045                        // hashing method.
1046                        self.cookie.set_processing_csf_message();
1047
1048                        // We'll be looking for the signature framing next.
1049                        self.kind = Some(Kind::Signature);
1050                        break 'search len;
1051                    }
1052                    let kind = Kind::try_from(label)
1053                        .expect("cleartext signature handled above");
1054
1055                    let mut expected_kind = None;
1056                    if let ReaderMode::Tolerant(Some(kind)) = self.mode {
1057                        expected_kind = Some(kind);
1058                    }
1059
1060                    if expected_kind == None {
1061                        // Found any!
1062                        self.kind = Some(kind);
1063                        break 'search len;
1064                    }
1065
1066                    if expected_kind == Some(kind) {
1067                        // Found it!
1068                        self.kind = Some(kind);
1069                        break 'search len;
1070                    }
1071                }
1072
1073                if self.mode == ReaderMode::VeryTolerant {
1074                    // The user did not specify what kind of data she
1075                    // wants.  We aggressively try to decode any data,
1076                    // even if we do not see a valid header.
1077                    if is_armored_pgp_blob(input) {
1078                        found_blob = true;
1079                        break 'search 0;
1080                    }
1081                }
1082            }
1083        };
1084        self.source.consume(n);
1085        t!("self.kind is {:?} after consuming {} bytes", self.kind, n);
1086
1087        if found_blob {
1088            // Skip the rest of the initialization.
1089            self.initialized = true;
1090            self.prefix_remaining = prefix.len();
1091            self.prefix = prefix;
1092            return Ok(());
1093        }
1094
1095        self.prefix = prefix;
1096        self.read_headers()
1097    }
1098
1099    /// Reads headers and finishes the initialization.
1100    fn read_headers(&mut self) -> Result<()> {
1101        tracer!(TRACE, "armor::Reader::read_headers");
1102        // We consumed the header above, but not any trailing
1103        // whitespace and the trailing new line.  We do that now.
1104        // Other data between the header and the new line are not
1105        // allowed.  But, instead of failing, we try to recover, by
1106        // stopping at the first non-whitespace character.
1107        let n = {
1108            let line = self.source.read_to(b'\n')?;
1109            line.iter().position(|&c| {
1110                !c.is_ascii_whitespace()
1111            }).unwrap_or(line.len())
1112        };
1113        self.source.consume(n);
1114        t!("consumed {} bytes of whitespace", n);
1115
1116        let next_prefix =
1117            &self.source.data_hard(self.prefix.len())?[..self.prefix.len()];
1118        if self.prefix != next_prefix {
1119            // If the next line doesn't start with the same prefix, we assume
1120            // it was garbage on the front and drop the prefix so long as it
1121            // was purely whitespace.  Any non-whitespace remains an error
1122            // while searching for the armor header if it's not repeated.
1123            if self.prefix.iter().all(|b| (*b as char).is_ascii_whitespace()) {
1124                crate::vec_truncate(&mut self.prefix, 0);
1125            } else {
1126                // Nope, we have actually failed to read this properly
1127                return Err(
1128                    Error::new(ErrorKind::InvalidInput,
1129                               "Inconsistent quoting of armored data"));
1130            }
1131        }
1132
1133        // Read the key-value headers.
1134        let mut n = 0;
1135        // Sometimes, we find a truncated prefix.  In these cases, the
1136        // length is not prefix.len(), but this.
1137        let mut prefix_len = None;
1138        let mut lines = 0;
1139        loop {
1140            // Skip any known prefix on lines.
1141            //
1142            // IMPORTANT: We need to buffer the prefix so that we can
1143            // consume it here.  So at every point in this loop where
1144            // the control flow wraps around, we need to make sure
1145            // that we buffer the prefix in addition to the line.
1146            self.source.consume(
1147                prefix_len.take().unwrap_or_else(|| self.prefix.len()));
1148
1149            self.source.consume(n);
1150
1151            // Buffer the next line.
1152            let line = self.source.read_to(b'\n')?;
1153            n = line.len();
1154            t!("{}: {:?}", lines, String::from_utf8_lossy(&line));
1155            lines += 1;
1156
1157            let line = str::from_utf8(line);
1158            // Ignore---don't error out---lines that are not valid UTF8.
1159            if line.is_err() {
1160                // Buffer the next line and the prefix that is going
1161                // to be consumed in the next iteration.
1162                let next_prefix =
1163                    &self.source.data_hard(n + self.prefix.len())?
1164                        [n..n + self.prefix.len()];
1165                if self.prefix != next_prefix {
1166                    return Err(
1167                        Error::new(ErrorKind::InvalidInput,
1168                                   "Inconsistent quoting of armored data"));
1169                }
1170                continue;
1171            }
1172
1173            let line = line.unwrap();
1174
1175            // The line almost certainly ends with \n: the only reason
1176            // it couldn't is if we encountered EOF.  We need to strip
1177            // it.  But, if it ends with \r\n, then we also want to
1178            // strip the \r too.
1179            let line = if let Some(rest) = line.strip_suffix("\r\n") {
1180                // \r\n.
1181                rest
1182            } else if let Some(rest) = line.strip_suffix('\n') {
1183                // \n.
1184                rest
1185            } else {
1186                // EOF.
1187                line
1188            };
1189
1190            /* Process headers.  */
1191            let key_value = line.splitn(2, ": ").collect::<Vec<&str>>();
1192            if key_value.len() == 1 {
1193                if line.trim_start().is_empty() {
1194                    // Empty line.
1195                    break;
1196                } else if lines == 1 {
1197                    // This is the first line and we don't have a
1198                    // key-value pair.  It seems more likely that
1199                    // we're just missing a newline and this invalid
1200                    // header is actually part of the body.
1201                    n = 0;
1202                    break;
1203                }
1204            } else {
1205                let key = key_value[0].trim_start();
1206                let value = key_value[1];
1207
1208                self.headers.push((key.into(), value.into()));
1209            }
1210
1211            // Buffer the next line and the prefix that is going to be
1212            // consumed in the next iteration.
1213            let next_prefix =
1214                &self.source.data_hard(n + self.prefix.len())?
1215                    [n..n + self.prefix.len()];
1216
1217            // Sometimes, we find a truncated prefix.
1218            let l = common_prefix(&self.prefix, next_prefix);
1219            let full_prefix = l == self.prefix.len();
1220            if ! (full_prefix
1221                  // Truncation is okay if the rest of the prefix
1222                  // contains only whitespace.
1223                  || self.prefix[l..].iter().all(|c| c.is_ascii_whitespace()))
1224            {
1225                return Err(
1226                    Error::new(ErrorKind::InvalidInput,
1227                               "Inconsistent quoting of armored data"));
1228            }
1229            if ! full_prefix {
1230                // Make sure to only consume the truncated prefix in
1231                // the next loop iteration.
1232                prefix_len = Some(l);
1233            }
1234        }
1235        self.source.consume(n);
1236
1237        self.initialized = true;
1238        self.prefix_remaining = self.prefix.len();
1239        Ok(())
1240    }
1241}
1242
1243/// Computes the length of the common prefix.
1244fn common_prefix<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: A, b: B) -> usize {
1245    a.as_ref().iter().zip(b.as_ref().iter()).take_while(|(a, b)| a == b).count()
1246}
1247
1248impl<'a> Reader<'a> {
1249    fn read_armored_data(&mut self, buf: &mut [u8]) -> Result<usize> {
1250        assert!(self.csft.is_none());
1251
1252        let (consumed, decoded) = if !self.decode_buffer.is_empty() {
1253            // We have something buffered, use that.
1254
1255            let amount = cmp::min(buf.len(), self.decode_buffer.len());
1256            buf[..amount].copy_from_slice(&self.decode_buffer[..amount]);
1257            crate::vec_drain_prefix(&mut self.decode_buffer, amount);
1258
1259            (0, amount)
1260        } else {
1261            // We need to decode some data.  We consider three cases,
1262            // all a function of the size of `buf`:
1263            //
1264            //   - Tiny: if `buf` can hold less than three bytes, then
1265            //     we almost certainly have to double buffer: except
1266            //     at the very end, a base64 chunk consists of 3 bytes
1267            //     of data.
1268            //
1269            //     Note: this happens if the caller does `for c in
1270            //     Reader::from_reader(...).bytes() ...`.  Then it
1271            //     reads one byte of decoded data at a time.
1272            //
1273            //   - Small: if the caller only requests a few bytes at a
1274            //     time, we may as well double buffer to reduce
1275            //     decoding overhead.
1276            //
1277            //   - Large: if `buf` is large, we can decode directly
1278            //     into `buf` and avoid double buffering.  But,
1279            //     because we ignore whitespace, it is hard to
1280            //     determine exactly how much data to read to
1281            //     maximally fill `buf`.
1282
1283            // We use 64, because ASCII-armor text usually contains 64
1284            // characters of base64 data per line, and this prevents
1285            // turning the borrow into an own.
1286            const THRESHOLD : usize = 64;
1287
1288            let to_read =
1289                cmp::max(
1290                    // Tiny or small:
1291                    THRESHOLD + 2,
1292
1293                    // Large: a heuristic:
1294
1295                    base64_size(buf.len())
1296                    // Assume about 2 bytes of whitespace (crlf) per
1297                    // 64 character line.
1298                        + 2 * ((buf.len() + 63) / 64));
1299
1300            let base64data = self.source.data(to_read)?;
1301            let base64data = if base64data.len() > to_read {
1302                &base64data[..to_read]
1303            } else {
1304                base64data
1305            };
1306
1307            let (base64data, consumed, prefix_remaining)
1308                = base64_filter(Cow::Borrowed(base64data),
1309                                // base64_size rounds up, but we want
1310                                // to round down as we have to double
1311                                // buffer partial chunks.
1312                                cmp::max(THRESHOLD, buf.len() / 3 * 4),
1313                                self.prefix_remaining,
1314                                self.prefix.len());
1315
1316            // We shouldn't have any partial chunks.
1317            assert_eq!(base64data.len() % 4, 0);
1318
1319            let decoded = if base64data.len() / 4 * 3 > buf.len() {
1320                // We need to double buffer.  Decode into a vector.
1321                // (Note: the computed size *might* be a slight
1322                // overestimate, because the last base64 chunk may
1323                // include padding.)
1324                self.decode_buffer = base64std.decode(&base64data)
1325                    .map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
1326
1327                let copied = cmp::min(buf.len(), self.decode_buffer.len());
1328                buf[..copied].copy_from_slice(&self.decode_buffer[..copied]);
1329                crate::vec_drain_prefix(&mut self.decode_buffer, copied);
1330
1331                copied
1332            } else {
1333                // We can decode directly into the caller-supplied
1334                // buffer.
1335                base64std.decode_slice(&base64data, buf)
1336                    .map_err(|e| Error::new(ErrorKind::InvalidData, e))?
1337            };
1338
1339            self.prefix_remaining = prefix_remaining;
1340
1341            (consumed, decoded)
1342        };
1343
1344        self.source.consume(consumed);
1345        if decoded == 0 {
1346            self.finalized = true;
1347
1348            /* Look for CRC.  The CRC is optional.  */
1349            let consumed = {
1350                // Skip whitespace.
1351                while !self.source.data(1)?.is_empty()
1352                    && self.source.buffer()[0].is_ascii_whitespace()
1353                {
1354                    self.source.consume(1);
1355                }
1356
1357                let data = self.source.data(5)?;
1358                let data = if data.len() > 5 {
1359                    &data[..5]
1360                } else {
1361                    data
1362                };
1363
1364                if data.len() == 5
1365                    && data[0] == b'='
1366                    && data[1..5].iter().all(is_base64_char)
1367                {
1368                    /* Found.  */
1369                    5
1370                } else {
1371                    0
1372                }
1373            };
1374            self.source.consume(consumed);
1375
1376            // Skip any expected prefix
1377            self.source.data_consume_hard(self.prefix.len())?;
1378            // Look for a footer.
1379            let consumed = {
1380                // Skip whitespace.
1381                while !self.source.data(1)?.is_empty()
1382                    && self.source.buffer()[0].is_ascii_whitespace()
1383                {
1384                    self.source.consume(1);
1385                }
1386
1387                // If we had a header, we require a footer.
1388                if let Some(kind) = self.kind {
1389                    let footer_lookahead = 128; // Why not.
1390                    let got = self.source.data(footer_lookahead)?;
1391                    let got = if got.len() > footer_lookahead {
1392                        &got[..footer_lookahead]
1393                    } else {
1394                        got
1395                    };
1396                    if let Some(footer_len) = kind.detect_footer(got) {
1397                        footer_len
1398                    } else {
1399                        return Err(Error::new(ErrorKind::InvalidInput,
1400                                              "Invalid ASCII Armor footer."));
1401                    }
1402                } else {
1403                    0
1404                }
1405            };
1406            self.source.consume(consumed);
1407        }
1408
1409        Ok(decoded)
1410    }
1411
1412    /// Reads a message using the Cleartext Signature Framework,
1413    /// transforms it into an inline-signed message, then feeds that
1414    /// to the consumer.
1415    fn read_clearsigned_message(&mut self, buf: &mut [u8])
1416                                -> crate::Result<usize>
1417    {
1418        assert!(self.csft.is_some());
1419
1420        use crate::{
1421            parse::{
1422                Dearmor,
1423                PacketParserBuilder,
1424                PacketParserResult,
1425                Parse,
1426            },
1427            serialize::Serialize,
1428            types::DataFormat,
1429        };
1430
1431        if self.csft == Some(CSFTransformer::Transform) {
1432            // Read the text body.
1433            let literal = {
1434                let mut text = Vec::new();
1435                loop {
1436                    let prefixed_line = self.source.read_to(b'\n')?;
1437
1438                    if prefixed_line.is_empty() {
1439                        // Truncated?
1440                        break;
1441                    }
1442
1443                    // Treat lines shorter than the prefix as
1444                    // empty lines.
1445                    let n = prefixed_line.len().min(self.prefix.len());
1446                    let prefix = &prefixed_line[..n];
1447                    let mut line = &prefixed_line[n..];
1448
1449                    // Check that we see the correct prefix.
1450                    let l = common_prefix(&self.prefix, prefix);
1451                    let full_prefix = l == self.prefix.len();
1452                    if ! (full_prefix
1453                          // Truncation is okay if the rest of the prefix
1454                          // contains only whitespace.
1455                          || self.prefix[l..].iter().all(
1456                              |c| c.is_ascii_whitespace()))
1457                    {
1458                        return Err(
1459                            Error::new(ErrorKind::InvalidInput,
1460                                       "Inconsistent quoting of \
1461                                        armored data").into());
1462                    }
1463
1464                    let (dashes, rest) = dash_prefix(line);
1465                    if dashes.len() > 2 // XXX: heuristic...
1466                        && rest.starts_with(b"BEGIN PGP SIGNATURE")
1467                    {
1468                        // We reached the end of the signed
1469                        // message.  Consuming this line and break
1470                        // the loop.
1471                        let l = prefixed_line.len();
1472                        self.source.consume(l);
1473                        break;
1474                    }
1475
1476                    // Undo the dash-escaping.
1477                    if line.starts_with(b"- ") {
1478                        line = &line[2..];
1479                    }
1480
1481                    // Trim trailing whitespace according to Section
1482                    // 7.1 of RFC4880, i.e. "spaces (0x20) and tabs
1483                    // (0x09)".  We do this here, because we transform
1484                    // the CSF message into an inline signed message,
1485                    // which does not make a distinction between the
1486                    // literal text and the signed text (modulo the
1487                    // newline normalization).
1488
1489                    // First, split off the line ending.
1490                    let crlf_line_end = line.ends_with(b"\r\n");
1491                    line = &line[..line.len().saturating_sub(
1492                        if crlf_line_end { 2 } else { 1 })];
1493
1494                    // Now, trim whitespace off the line.
1495                    while Some(&b' ') == line.last()
1496                        || Some(&b'\t') == line.last()
1497                    {
1498                        line = &line[..line.len().saturating_sub(1)];
1499                    }
1500
1501                    text.extend_from_slice(line);
1502                    if crlf_line_end {
1503                        text.extend_from_slice(&b"\r\n"[..]);
1504                    } else {
1505                        text.extend_from_slice(&b"\n"[..]);
1506                    }
1507
1508                    // Finally, consume this line.
1509                    let l = prefixed_line.len();
1510                    self.source.consume(l);
1511                }
1512
1513                // Trim the final newline, it is not part of the
1514                // message, but separates the signature marker from
1515                // the text.
1516                let c = text.pop();
1517                assert!(c.is_none() || c == Some(b'\n'));
1518                if text.ends_with(b"\r") {
1519                    text.pop();
1520                }
1521
1522                // Now, we have the whole text.
1523                // XXX: We optimistically assume that it is UTF-8 encoded.
1524                let mut literal = Literal::new(DataFormat::Unicode);
1525                literal.set_body(text);
1526                literal
1527            };
1528
1529            // Then, read and parse all the signatures.  To that end,
1530            // we need to temporarily disable the CSF transformation,
1531            // and doing that will finalize the reader, which we'll
1532            // have to undo later on.
1533            self.csft = None;
1534
1535            // We found the signature marker, now consume any armor
1536            // headers.
1537            self.read_headers()?;
1538
1539            let mut sigs: Vec<Packet> = Vec::new();
1540            let mut ppr = PacketParserBuilder::from_reader(self.by_ref())?
1541                .dearmor(Dearmor::Disabled)
1542                .build()?;
1543            while let PacketParserResult::Some(pp) = ppr {
1544                let (p, ppr_) = pp.next()?;
1545                match p {
1546                    Packet::Signature(sig) => sigs.push(sig.into()),
1547                    Packet::Marker(_) => (),
1548                    Packet::Unknown(u) if u.tag() == Tag::Signature =>
1549                        sigs.push(u.into()),
1550                    p => return Err(crate::Error::MalformedMessage(
1551                        format!("Unexpected {} packet in \
1552                                 cleartext signed message", p.tag()))
1553                                    .into()),
1554                }
1555                ppr = ppr_;
1556            }
1557            drop(ppr);
1558            assert!(self.finalized);
1559
1560            // Now assemble an inline-signed message from the text
1561            // and components.
1562
1563            // First, create one-pass-signature packets, and mark
1564            // the last of them as being the last.
1565            let mut opss = Vec::with_capacity(sigs.len());
1566            for p in sigs.iter().rev() {
1567                if let Packet::Signature(sig) = p {
1568                    if let Ok(ops) = OnePassSig::try_from(sig) {
1569                        opss.push(ops);
1570                    }
1571                }
1572            }
1573            if let Some(ops) = opss.last_mut() {
1574                ops.set_last(true);
1575            }
1576
1577            // Now write everything out to our buffer.
1578            for ops in opss {
1579                Packet::from(ops).serialize(&mut self.decode_buffer)?;
1580            }
1581            Packet::from(literal).serialize(&mut self.decode_buffer)?;
1582            for p in sigs {
1583                p.serialize(&mut self.decode_buffer)?;
1584            }
1585
1586            // We have placed the assembled message into our decode
1587            // buffer.  Now revert the reader to a state so that the
1588            // caller can extract it.
1589            self.finalized = false;
1590            self.eof = false;
1591            self.csft = Some(CSFTransformer::Read);
1592        }
1593
1594        let amount = cmp::min(buf.len(), self.decode_buffer.len());
1595        buf[..amount].copy_from_slice(&self.decode_buffer[..amount]);
1596        crate::vec_drain_prefix(&mut self.decode_buffer, amount);
1597        Ok(amount)
1598    }
1599
1600    /// The io::Read interface that the embedded generic reader uses
1601    /// to implement the BufferedReader protocol.
1602    fn do_read(&mut self, buf: &mut [u8]) -> Result<usize> {
1603        if ! self.initialized {
1604            self.initialize()?;
1605        }
1606
1607        if buf.is_empty() {
1608            // Short-circuit here.  Otherwise, we copy 0 bytes into
1609            // the buffer, which means we decoded 0 bytes, and we
1610            // wrongfully assume that we reached the end of the
1611            // armored block.
1612            return Ok(0);
1613        }
1614
1615        if self.finalized {
1616            assert_eq!(self.decode_buffer.len(), 0);
1617            return Ok(0);
1618        }
1619
1620        if self.csft.is_some() {
1621            self.read_clearsigned_message(buf)
1622                .map_err(|e| {
1623                    match e.downcast::<io::Error>() {
1624                        Ok(e) => e,
1625                        Err(e) => io::Error::new(io::ErrorKind::Other, e),
1626                    }
1627                })
1628        } else {
1629            self.read_armored_data(buf)
1630        }
1631    }
1632
1633    /// Return the buffer.  Ensure that it contains at least `amount`
1634    /// bytes.
1635    // XXX: This is a verbatim copy of
1636    // buffered_reader::Generic::data_helper, the only modification is
1637    // that it uses the above do_read function.
1638    fn data_helper(&mut self, amount: usize, hard: bool, and_consume: bool)
1639                   -> io::Result<&[u8]> {
1640        tracer!(TRACE, "armor::Reader::data_helper");
1641        t!("amount: {}, hard: {}, and_consume: {} (cursor: {}, buffer: {:?})",
1642           amount, hard, and_consume,
1643           self.cursor,
1644           self.buffer.as_ref().map(|buffer| buffer.len()));
1645
1646        if let Some(ref buffer) = self.buffer {
1647            // We have a buffer.  Make sure `cursor` is sane.
1648            assert!(self.cursor <= buffer.len());
1649        } else {
1650            // We don't have a buffer.  Make sure cursor is 0.
1651            assert_eq!(self.cursor, 0);
1652        }
1653
1654        let amount_buffered
1655            = self.buffer.as_ref().map(|b| b.len() - self.cursor).unwrap_or(0);
1656        if amount > amount_buffered {
1657            // The caller wants more data than we have readily
1658            // available.  Read some more.
1659
1660            let capacity : usize = amount.saturating_add(
1661                DEFAULT_BUF_SIZE.max(
1662                    self.preferred_chunk_size.saturating_mul(2)));
1663
1664            let mut buffer_new = self.unused_buffer.take()
1665                .map(|mut v| {
1666                    vec_resize(&mut v, capacity);
1667                    v
1668                })
1669                .unwrap_or_else(|| vec![0u8; capacity]);
1670
1671            let mut amount_read = 0;
1672            while amount_buffered + amount_read < amount {
1673                t!("Have {} bytes, need {} bytes",
1674                   amount_buffered + amount_read, amount);
1675
1676                if self.eof {
1677                    t!("Hit EOF on the underlying reader, don't poll again.");
1678                    break;
1679                }
1680
1681                // See if there is an error from the last invocation.
1682                if let Some(e) = &self.error {
1683                    t!("We have a stashed error, don't poll again: {}", e);
1684                    break;
1685                }
1686
1687                match self.do_read(&mut buffer_new
1688                                   [amount_buffered + amount_read..]) {
1689                    Ok(read) => {
1690                        t!("Read {} bytes", read);
1691                        if read == 0 {
1692                            self.eof = true;
1693                            break;
1694                        } else {
1695                            amount_read += read;
1696                            continue;
1697                        }
1698                    },
1699                    Err(ref err) if err.kind() == ErrorKind::Interrupted =>
1700                        continue,
1701                    Err(err) => {
1702                        // Don't return yet, because we may have
1703                        // actually read something.
1704                        self.error = Some(err);
1705                        break;
1706                    },
1707                }
1708            }
1709
1710            if amount_read > 0 {
1711                // We read something.
1712                if let Some(ref buffer) = self.buffer {
1713                    // We need to copy in the old data.
1714                    buffer_new[0..amount_buffered]
1715                        .copy_from_slice(
1716                            &buffer[self.cursor..self.cursor + amount_buffered]);
1717                }
1718
1719                vec_truncate(&mut buffer_new, amount_buffered + amount_read);
1720
1721                self.unused_buffer = self.buffer.take();
1722                self.buffer = Some(buffer_new);
1723                self.cursor = 0;
1724            }
1725        }
1726
1727        let amount_buffered
1728            = self.buffer.as_ref().map(|b| b.len() - self.cursor).unwrap_or(0);
1729
1730        if self.error.is_some() {
1731            t!("Encountered an error: {}", self.error.as_ref().unwrap());
1732            // An error occurred.  If we have enough data to fulfill
1733            // the caller's request, then don't return the error.
1734            if hard && amount > amount_buffered {
1735                t!("Not enough data to fulfill request, returning error");
1736                return Err(self.error.take().unwrap());
1737            }
1738            if !hard && amount_buffered == 0 {
1739                t!("No data data buffered, returning error");
1740                return Err(self.error.take().unwrap());
1741            }
1742        }
1743
1744        if hard && amount_buffered < amount {
1745            t!("Unexpected EOF");
1746            Err(Error::new(ErrorKind::UnexpectedEof, "EOF"))
1747        } else if amount == 0 || amount_buffered == 0 {
1748            t!("Returning zero-length slice");
1749            Ok(&b""[..])
1750        } else {
1751            let buffer = self.buffer.as_ref().unwrap();
1752            if and_consume {
1753                let amount_consumed = cmp::min(amount_buffered, amount);
1754                self.cursor += amount_consumed;
1755                assert!(self.cursor <= buffer.len());
1756                t!("Consuming {} bytes, returning {} bytes",
1757                   amount_consumed,
1758                   buffer[self.cursor-amount_consumed..].len());
1759                Ok(&buffer[self.cursor-amount_consumed..])
1760            } else {
1761                t!("Returning {} bytes",
1762                   buffer[self.cursor..].len());
1763                Ok(&buffer[self.cursor..])
1764            }
1765        }
1766    }
1767}
1768
1769impl io::Read for Reader<'_> {
1770    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
1771        buffered_reader::buffered_reader_generic_read_impl(self, buf)
1772    }
1773}
1774
1775impl BufferedReader<Cookie> for Reader<'_> {
1776    fn buffer(&self) -> &[u8] {
1777        if let Some(ref buffer) = self.buffer {
1778            &buffer[self.cursor..]
1779        } else {
1780            &b""[..]
1781        }
1782    }
1783
1784    fn data(&mut self, amount: usize) -> Result<&[u8]> {
1785        self.data_helper(amount, false, false)
1786    }
1787
1788    fn data_hard(&mut self, amount: usize) -> Result<&[u8]> {
1789        self.data_helper(amount, true, false)
1790    }
1791
1792    fn consume(&mut self, amount: usize) -> &[u8] {
1793        // println!("Generic.consume({}) \
1794        //           (cursor: {}, buffer: {:?})",
1795        //          amount, self.cursor,
1796        //          if let Some(ref buffer) = self.buffer { Some(buffer.len()) }
1797        //          else { None });
1798
1799        // The caller can't consume more than is buffered!
1800        if let Some(ref buffer) = self.buffer {
1801            assert!(self.cursor <= buffer.len());
1802            assert!(amount <= buffer.len() - self.cursor,
1803                    "buffer contains just {} bytes, but you are trying to \
1804                    consume {} bytes.  Did you forget to call data()?",
1805                    buffer.len() - self.cursor, amount);
1806
1807            self.cursor += amount;
1808            return &self.buffer.as_ref().unwrap()[self.cursor - amount..];
1809        } else {
1810            assert_eq!(amount, 0);
1811            &b""[..]
1812        }
1813    }
1814
1815    fn data_consume(&mut self, amount: usize) -> Result<&[u8]> {
1816        self.data_helper(amount, false, true)
1817    }
1818
1819    fn data_consume_hard(&mut self, amount: usize) -> Result<&[u8]> {
1820        self.data_helper(amount, true, true)
1821    }
1822
1823    fn get_mut(&mut self) -> Option<&mut dyn BufferedReader<Cookie>> {
1824        Some(&mut self.source)
1825    }
1826
1827    fn get_ref(&self) -> Option<&dyn BufferedReader<Cookie>> {
1828        Some(&self.source)
1829    }
1830
1831    fn into_inner<'b>(self: Box<Self>)
1832                      -> Option<Box<dyn BufferedReader<Cookie> + 'b>>
1833        where Self: 'b {
1834        Some(self.source)
1835    }
1836
1837    fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
1838        std::mem::replace(&mut self.cookie, cookie)
1839    }
1840
1841    fn cookie_ref(&self) -> &Cookie {
1842        &self.cookie
1843    }
1844
1845    fn cookie_mut(&mut self) -> &mut Cookie {
1846        &mut self.cookie
1847    }
1848}
1849
1850/// Returns all character from Unicode's "Dash Punctuation" category.
1851fn dashes() -> impl Iterator<Item = char> {
1852    ['\u{002D}', // - (Hyphen-Minus)
1853     '\u{058A}', // ֊ (Armenian Hyphen)
1854     '\u{05BE}', // ־ (Hebrew Punctuation Maqaf)
1855     '\u{1400}', // ᐀ (Canadian Syllabics Hyphen)
1856     '\u{1806}', // ᠆ (Mongolian Todo Soft Hyphen)
1857     '\u{2010}', // ‐ (Hyphen)
1858     '\u{2011}', // ‑ (Non-Breaking Hyphen)
1859     '\u{2012}', // ‒ (Figure Dash)
1860     '\u{2013}', // – (En Dash)
1861     '\u{2014}', // — (Em Dash)
1862     '\u{2015}', // ― (Horizontal Bar)
1863     '\u{2E17}', // ⸗ (Double Oblique Hyphen)
1864     '\u{2E1A}', // ⸚ (Hyphen with Diaeresis)
1865     '\u{2E3A}', // ⸺ (Two-Em Dash)
1866     '\u{2E3B}', // ⸻ (Three-Em Dash)
1867     '\u{2E40}', // ⹀ (Double Hyphen)
1868     '\u{301C}', // 〜 (Wave Dash)
1869     '\u{3030}', // 〰 (Wavy Dash)
1870     '\u{30A0}', // ゠ (Katakana-Hiragana Double Hyphen)
1871     '\u{FE31}', // ︱ (Presentation Form For Vertical Em Dash)
1872     '\u{FE32}', // ︲ (Presentation Form For Vertical En Dash)
1873     '\u{FE58}', // ﹘ (Small Em Dash)
1874     '\u{FE63}', // ﹣ (Small Hyphen-Minus)
1875     '\u{FF0D}', // - (Fullwidth Hyphen-Minus)
1876    ].iter().cloned()
1877}
1878
1879/// Splits the given slice into a prefix of dashes and the rest.
1880///
1881/// Accepts any character from Unicode's "Dash Punctuation" category.
1882/// Assumes that the prefix containing the dashes is ASCII or UTF-8.
1883fn dash_prefix(d: &[u8]) -> (&[u8], &[u8]) {
1884    // First, compute a valid UTF-8 prefix.
1885    let p = match std::str::from_utf8(d) {
1886        Ok(u) => u,
1887        Err(e) => std::str::from_utf8(&d[..e.valid_up_to()])
1888            .expect("valid up to this point"),
1889    };
1890    let mut prefix_len = 0;
1891    for c in p.chars() {
1892        // Keep going while we see characters from the Category "Dash
1893        // Punctuation".
1894        match c {
1895            '\u{002D}' // - (Hyphen-Minus)
1896                | '\u{058A}' // ֊ (Armenian Hyphen)
1897                | '\u{05BE}' // ־ (Hebrew Punctuation Maqaf)
1898                | '\u{1400}' // ᐀ (Canadian Syllabics Hyphen)
1899                | '\u{1806}' // ᠆ (Mongolian Todo Soft Hyphen)
1900                | '\u{2010}' // ‐ (Hyphen)
1901                | '\u{2011}' // ‑ (Non-Breaking Hyphen)
1902                | '\u{2012}' // ‒ (Figure Dash)
1903                | '\u{2013}' // – (En Dash)
1904                | '\u{2014}' // — (Em Dash)
1905                | '\u{2015}' // ― (Horizontal Bar)
1906                | '\u{2E17}' // ⸗ (Double Oblique Hyphen)
1907                | '\u{2E1A}' // ⸚ (Hyphen with Diaeresis)
1908                | '\u{2E3A}' // ⸺ (Two-Em Dash)
1909                | '\u{2E3B}' // ⸻ (Three-Em Dash)
1910                | '\u{2E40}' // ⹀ (Double Hyphen)
1911                | '\u{301C}' // 〜 (Wave Dash)
1912                | '\u{3030}' // 〰 (Wavy Dash)
1913                | '\u{30A0}' // ゠ (Katakana-Hiragana Double Hyphen)
1914                | '\u{FE31}' // ︱ (Presentation Form For Vertical Em Dash)
1915                | '\u{FE32}' // ︲ (Presentation Form For Vertical En Dash)
1916                | '\u{FE58}' // ﹘ (Small Em Dash)
1917                | '\u{FE63}' // ﹣ (Small Hyphen-Minus)
1918                | '\u{FF0D}' // - (Fullwidth Hyphen-Minus)
1919              => prefix_len += c.len_utf8(),
1920            _ => break,
1921        }
1922    }
1923
1924    (&d[..prefix_len], &d[prefix_len..])
1925}
1926
1927#[cfg(test)]
1928mod test {
1929    use std::io::{Cursor, Read, Write};
1930    use super::Kind;
1931    use super::Writer;
1932
1933    macro_rules! t {
1934        ( $path: expr ) => {
1935            include_bytes!(concat!("../tests/data/armor/", $path))
1936        }
1937    }
1938    macro_rules! vectors {
1939        ( $prefix: expr, $suffix: expr ) => {
1940            &[t!(concat!($prefix, "-0", $suffix)),
1941              t!(concat!($prefix, "-1", $suffix)),
1942              t!(concat!($prefix, "-2", $suffix)),
1943              t!(concat!($prefix, "-3", $suffix)),
1944              t!(concat!($prefix, "-47", $suffix)),
1945              t!(concat!($prefix, "-48", $suffix)),
1946              t!(concat!($prefix, "-49", $suffix)),
1947              t!(concat!($prefix, "-50", $suffix)),
1948              t!(concat!($prefix, "-51", $suffix))]
1949        }
1950    }
1951
1952    const TEST_BIN: &[&[u8]] = vectors!("test", ".bin");
1953    const TEST_ASC: &[&[u8]] = vectors!("test", ".asc");
1954    const LITERAL_BIN: &[&[u8]] = vectors!("literal", ".bin");
1955    const LITERAL_ASC: &[&[u8]] = vectors!("literal", ".asc");
1956    const LITERAL_NO_HEADER_ASC: &[&[u8]] =
1957        vectors!("literal", "-no-header.asc");
1958    const LITERAL_NO_HEADER_WITH_CHKSUM_ASC: &[&[u8]] =
1959        vectors!("literal", "-no-header-with-chksum.asc");
1960    const LITERAL_NO_NEWLINES_ASC: &[&[u8]] =
1961        vectors!("literal", "-no-newlines.asc");
1962
1963    #[test]
1964    fn enarmor() {
1965        for (i, (bin, asc)) in TEST_BIN.iter().zip(TEST_ASC.iter()).enumerate()
1966        {
1967            eprintln!("Test {}", i);
1968            let mut w =
1969                Writer::new(Vec::new(), Kind::File).unwrap();
1970            w.write(&[]).unwrap();  // Avoid zero-length optimization.
1971            w.write_all(bin).unwrap();
1972            let buf = w.finalize().unwrap();
1973            assert_eq!(String::from_utf8_lossy(&buf),
1974                       String::from_utf8_lossy(asc));
1975        }
1976    }
1977
1978    #[test]
1979    fn enarmor_bytewise() {
1980        for (bin, asc) in TEST_BIN.iter().zip(TEST_ASC.iter()) {
1981            let mut w = Writer::new(Vec::new(), Kind::File).unwrap();
1982            w.write(&[]).unwrap();  // Avoid zero-length optimization.
1983            for b in bin.iter() {
1984                w.write(&[*b]).unwrap();
1985            }
1986            let buf = w.finalize().unwrap();
1987            assert_eq!(String::from_utf8_lossy(&buf),
1988                       String::from_utf8_lossy(asc));
1989        }
1990    }
1991
1992    #[test]
1993    fn drop_writer() {
1994        // No ASCII frame shall be emitted if the writer is dropped
1995        // unused.
1996        assert!(Writer::new(Vec::new(), Kind::File).unwrap()
1997                .finalize().unwrap().is_empty());
1998
1999        // However, if the user insists, we will encode a zero-byte
2000        // string.
2001        let mut w = Writer::new(Vec::new(), Kind::File).unwrap();
2002        w.write(&[]).unwrap();
2003        let buf = w.finalize().unwrap();
2004        assert_eq!(
2005            &buf[..],
2006            &b"-----BEGIN PGP ARMORED FILE-----\n\
2007               \n\
2008               =twTO\n\
2009               -----END PGP ARMORED FILE-----\n"[..]);
2010    }
2011
2012    use super::{Reader, ReaderMode};
2013
2014    #[test]
2015    fn dearmor_robust() {
2016        for (i, reference) in LITERAL_BIN.iter().enumerate() {
2017            for test in &[LITERAL_ASC[i],
2018                          LITERAL_NO_HEADER_WITH_CHKSUM_ASC[i],
2019                          LITERAL_NO_HEADER_ASC[i],
2020                          LITERAL_NO_NEWLINES_ASC[i]] {
2021                let mut r = Reader::from_reader(Cursor::new(test),
2022                                        ReaderMode::VeryTolerant);
2023                let mut dearmored = Vec::<u8>::new();
2024                r.read_to_end(&mut dearmored).unwrap();
2025
2026                assert_eq!(&dearmored, reference);
2027            }
2028        }
2029    }
2030
2031    #[test]
2032    fn dearmor_binary() {
2033        for bin in TEST_BIN.iter() {
2034            let mut r = Reader::from_reader(
2035                Cursor::new(bin), ReaderMode::Tolerant(Some(Kind::Message)));
2036            let mut buf = [0; 5];
2037            let e = r.read(&mut buf);
2038            assert!(e.is_err());
2039        }
2040    }
2041
2042    #[test]
2043    fn dearmor_wrong_kind() {
2044        let mut r = Reader::from_reader(
2045            Cursor::new(&include_bytes!("../tests/data/armor/test-0.asc")[..]),
2046            ReaderMode::Tolerant(Some(Kind::Message)));
2047        let mut buf = [0; 5];
2048        let e = r.read(&mut buf);
2049        assert!(e.is_err());
2050    }
2051
2052    #[test]
2053    fn dearmor_wrong_crc() {
2054        let mut r = Reader::from_reader(
2055            Cursor::new(
2056                &include_bytes!("../tests/data/armor/test-0.bad-crc.asc")[..]),
2057            ReaderMode::Tolerant(Some(Kind::File)));
2058        let mut buf = [0; 5];
2059        let e = r.read(&mut buf);
2060        // Quoting RFC4880++:
2061        //
2062        // > An implementation MUST NOT reject an OpenPGP object when
2063        // > the CRC24 footer is present, missing, malformed, or
2064        // > disagrees with the computed CRC24 sum.
2065        assert!(e.is_ok());
2066    }
2067
2068    #[test]
2069    fn dearmor_wrong_footer() {
2070        let mut r = Reader::from_reader(
2071            Cursor::new(
2072                &include_bytes!("../tests/data/armor/test-2.bad-footer.asc")[..]
2073            ),
2074            ReaderMode::Tolerant(Some(Kind::File)));
2075        let mut read = 0;
2076        loop {
2077            let mut buf = [0; 5];
2078            match r.read(&mut buf) {
2079                Ok(0) => panic!("Reached EOF, but expected an error!"),
2080                Ok(r) => read += r,
2081                Err(_) => break,
2082            }
2083        }
2084        assert!(read <= 2);
2085    }
2086
2087    #[test]
2088    fn dearmor_no_crc() {
2089        let mut r = Reader::from_reader(
2090            Cursor::new(
2091                &include_bytes!("../tests/data/armor/test-1.no-crc.asc")[..]),
2092            ReaderMode::Tolerant(Some(Kind::File)));
2093        let mut buf = [0; 5];
2094        let e = r.read(&mut buf);
2095        assert!(e.unwrap() == 1 && buf[0] == 0xde);
2096    }
2097
2098    #[test]
2099    fn dearmor_with_header() {
2100        let mut r = Reader::from_reader(
2101            Cursor::new(
2102                &include_bytes!("../tests/data/armor/test-3.with-headers.asc")[..]
2103            ),
2104            ReaderMode::Tolerant(Some(Kind::File)));
2105        assert_eq!(r.headers().unwrap(),
2106                   &[("Comment".into(), "Some Header".into()),
2107                     ("Comment".into(), "Another one".into())]);
2108        let mut buf = [0; 5];
2109        let e = r.read(&mut buf);
2110        assert!(e.is_ok());
2111        assert_eq!(e.unwrap(), 3);
2112        assert_eq!(&buf[..3], TEST_BIN[3]);
2113    }
2114
2115    #[test]
2116    fn dearmor_any() {
2117        let mut r = Reader::from_reader(
2118            Cursor::new(
2119                &include_bytes!("../tests/data/armor/test-3.with-headers.asc")[..]
2120            ),
2121            ReaderMode::VeryTolerant);
2122        let mut buf = [0; 5];
2123        let e = r.read(&mut buf);
2124        assert_eq!(r.kind(), Some(Kind::File));
2125        assert!(e.is_ok());
2126        assert_eq!(e.unwrap(), 3);
2127        assert_eq!(&buf[..3], TEST_BIN[3]);
2128    }
2129
2130    #[test]
2131    fn dearmor_with_garbage() {
2132        let armored =
2133            include_bytes!("../tests/data/armor/test-3.with-headers.asc");
2134        // Slap some garbage in front and make sure it still reads ok.
2135        let mut b: Vec<u8> = "Some\ngarbage\nlines\n\t\r  ".into();
2136        b.extend_from_slice(armored);
2137        let mut r = Reader::from_reader(Cursor::new(b), ReaderMode::VeryTolerant);
2138        let mut buf = [0; 5];
2139        let e = r.read(&mut buf);
2140        assert_eq!(r.kind(), Some(Kind::File));
2141        assert!(e.is_ok());
2142        assert_eq!(e.unwrap(), 3);
2143        assert_eq!(&buf[..3], TEST_BIN[3]);
2144
2145        // Again, but this time add a non-whitespace character in the
2146        // line of the header.
2147        let mut b: Vec<u8> = "Some\ngarbage\nlines\n\t.\r  ".into();
2148        b.extend_from_slice(armored);
2149        let mut r = Reader::from_reader(Cursor::new(b), ReaderMode::VeryTolerant);
2150        let mut buf = [0; 5];
2151        let e = r.read(&mut buf);
2152        assert!(e.is_err());
2153    }
2154
2155    #[test]
2156    fn dearmor() {
2157        for (bin, asc) in TEST_BIN.iter().zip(TEST_ASC.iter()) {
2158            let mut r = Reader::from_reader(
2159                Cursor::new(asc),
2160                ReaderMode::Tolerant(Some(Kind::File)));
2161            let mut dearmored = Vec::<u8>::new();
2162            r.read_to_end(&mut dearmored).unwrap();
2163
2164            assert_eq!(&dearmored, bin);
2165        }
2166    }
2167
2168    #[test]
2169    fn dearmor_bytewise() {
2170        for (bin, asc) in TEST_BIN.iter().zip(TEST_ASC.iter()) {
2171            let r = Reader::from_reader(
2172                Cursor::new(asc),
2173                ReaderMode::Tolerant(Some(Kind::File)));
2174            let mut dearmored = Vec::<u8>::new();
2175            for c in r.bytes() {
2176                dearmored.push(c.unwrap());
2177            }
2178
2179            assert_eq!(&dearmored, bin);
2180        }
2181    }
2182
2183    #[test]
2184    fn dearmor_yuge() {
2185        let yuge_key = crate::tests::key("yuge-key-so-yuge-the-yugest.asc");
2186        let mut r = Reader::from_reader(Cursor::new(yuge_key),
2187                                ReaderMode::VeryTolerant);
2188        let mut dearmored = Vec::<u8>::new();
2189        r.read_to_end(&mut dearmored).unwrap();
2190
2191        let r = Reader::from_reader(Cursor::new(yuge_key),
2192                            ReaderMode::VeryTolerant);
2193        let mut dearmored = Vec::<u8>::new();
2194        for c in r.bytes() {
2195            dearmored.push(c.unwrap());
2196        }
2197    }
2198
2199    #[test]
2200    fn dearmor_quoted() {
2201        let mut r = Reader::from_reader(
2202            Cursor::new(
2203                &include_bytes!("../tests/data/armor/test-3.with-headers-quoted.asc")[..]
2204            ),
2205            ReaderMode::VeryTolerant);
2206        let mut buf = [0; 5];
2207        let e = r.read(&mut buf);
2208        assert_eq!(r.kind(), Some(Kind::File));
2209        assert!(e.is_ok());
2210        assert_eq!(e.unwrap(), 3);
2211        assert_eq!(&buf[..3], TEST_BIN[3]);
2212    }
2213
2214    #[test]
2215    fn dearmor_quoted_stripped() {
2216        let mut r = Reader::from_reader(
2217            Cursor::new(
2218                &include_bytes!("../tests/data/armor/test-3.with-headers-quoted-stripped.asc")[..]
2219            ),
2220            ReaderMode::VeryTolerant);
2221        let mut buf = [0; 5];
2222        let e = r.read(&mut buf);
2223        assert_eq!(r.kind(), Some(Kind::File));
2224        assert!(e.is_ok());
2225        assert_eq!(e.unwrap(), 3);
2226        assert_eq!(&buf[..3], TEST_BIN[3]);
2227    }
2228
2229    #[test]
2230    fn dearmor_quoted_a_lot() {
2231        let mut r = Reader::from_reader(
2232            Cursor::new(
2233                &include_bytes!("../tests/data/armor/test-3.with-headers-quoted-a-lot.asc")[..]
2234            ),
2235            ReaderMode::VeryTolerant);
2236        let mut buf = [0; 5];
2237        let e = r.read(&mut buf);
2238        assert_eq!(r.kind(), Some(Kind::File));
2239        assert!(e.is_ok());
2240        assert_eq!(e.unwrap(), 3);
2241        assert_eq!(&buf[..3], TEST_BIN[3]);
2242    }
2243
2244    #[test]
2245    fn dearmor_quoted_badly() {
2246        let mut r = Reader::from_reader(
2247            Cursor::new(
2248                &include_bytes!("../tests/data/armor/test-3.with-headers-quoted-badly.asc")[..]
2249            ),
2250            ReaderMode::VeryTolerant);
2251        let mut buf = [0; 5];
2252        let e = r.read(&mut buf);
2253        assert!(e.is_err());
2254    }
2255
2256    quickcheck! {
2257        fn roundtrip(kind: Kind, payload: Vec<u8>) -> bool {
2258            if payload.is_empty() {
2259                // Empty payloads do not emit an armor framing unless
2260                // one does an explicit empty write (and .write_all()
2261                // does not).
2262                return true;
2263            }
2264
2265            let mut w = Writer::new(Vec::new(), kind).unwrap();
2266            w.write_all(&payload).unwrap();
2267            let encoded = w.finalize().unwrap();
2268
2269            let mut recovered = Vec::new();
2270            Reader::from_reader(Cursor::new(&encoded),
2271                        ReaderMode::Tolerant(Some(kind)))
2272                .read_to_end(&mut recovered)
2273                .unwrap();
2274
2275            let mut recovered_any = Vec::new();
2276            Reader::from_reader(Cursor::new(&encoded), ReaderMode::VeryTolerant)
2277                .read_to_end(&mut recovered_any)
2278                .unwrap();
2279
2280            payload == recovered && payload == recovered_any
2281        }
2282    }
2283
2284    /// Tests issue #404, zero-sized reads break reader.
2285    ///
2286    /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/404
2287    #[test]
2288    fn zero_sized_read() {
2289        let mut r = Reader::from_bytes(crate::tests::file("armor/test-1.asc"),
2290                                       None);
2291        let mut buf = Vec::new();
2292        r.read(&mut buf).unwrap();
2293        r.read(&mut buf).unwrap();
2294    }
2295
2296    /// Crash in armor parser due to indexing not aligned with UTF-8
2297    /// characters.
2298    ///
2299    /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/515
2300    #[test]
2301    fn issue_515() {
2302        let data = [63, 9, 45, 10, 45, 10, 45, 45, 45, 45, 45, 66, 69,
2303                    71, 73, 78, 32, 80, 71, 80, 32, 77, 69, 83, 83,
2304                    65, 71, 69, 45, 45, 45, 45, 45, 45, 152, 152, 152,
2305                    152, 152, 152, 255, 29, 152, 152, 152, 152, 152,
2306                    152, 152, 152, 152, 152, 10, 91, 45, 10, 45, 14,
2307                    0, 36, 0, 0, 30, 122, 4, 2, 204, 152];
2308
2309        let mut reader = Reader::from_bytes(&data[..], None);
2310        let mut buf = Vec::new();
2311        // `data` is malformed, expect an error.
2312        reader.read_to_end(&mut buf).unwrap_err();
2313    }
2314
2315    /// Crash in armor parser due to improper use of the buffered
2316    /// reader protocol when consuming quoting prefix.
2317    ///
2318    /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/516
2319    #[test]
2320    fn issue_516() {
2321        let data = [
2322            144, 32, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 125, 13, 125,
2323            125, 93, 125, 125, 93, 125, 13, 13, 125, 125, 45, 45, 45,
2324            45, 45, 66, 69, 71, 73, 78, 32, 80, 71, 80, 32, 77, 69,
2325            83, 83, 65, 71, 69, 45, 45, 45, 45, 45, 125, 13, 125,
2326            125, 93, 125, 125, 93, 125, 13, 13, 125, 125, 45, 0, 0,
2327            0, 0, 0, 0, 0, 0, 125, 205, 21, 1, 21, 21, 21, 1, 1, 1,
2328            1, 21, 149, 21, 21, 21, 21, 32, 4, 141, 141, 141, 141,
2329            202, 74, 11, 125, 8, 21, 50, 50, 194, 48, 147, 93, 174,
2330            23, 23, 23, 23, 23, 23, 147, 147, 147, 23, 23, 23, 23,
2331            23, 23, 48, 125, 125, 93, 125, 13, 125, 125, 125, 93,
2332            125, 125, 13, 13, 125, 125, 13, 13, 93, 125, 13, 125, 45,
2333            125, 125, 45, 45, 66, 69, 71, 73, 78, 32, 80, 71, 45, 45,
2334            125, 10, 45, 45, 0, 0, 10, 45, 45, 210, 10, 0, 0, 87, 0,
2335            0, 0, 150, 10, 0, 0, 241, 87, 45, 0, 0, 121, 121, 10, 10,
2336            21, 58];
2337        let mut reader = Reader::from_bytes(&data[..], None);
2338        let mut buf = Vec::new();
2339        // `data` is malformed, expect an error.
2340        reader.read_to_end(&mut buf).unwrap_err();
2341    }
2342
2343    /// Crash in armor parser due to improper use of the buffered
2344    /// reader protocol when consuming quoting prefix.
2345    ///
2346    /// See: https://gitlab.com/sequoia-pgp/sequoia/-/issues/517
2347    #[test]
2348    fn issue_517() {
2349        let data = [13, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 80,
2350                    71, 80, 32, 77, 69, 83, 83, 65, 71, 69, 45, 45, 45,
2351                    45, 45, 10, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
2352                    13, 13, 139];
2353        let mut reader = Reader::from_bytes(&data[..], None);
2354        let mut buf = Vec::new();
2355        // `data` is malformed, expect an error.
2356        reader.read_to_end(&mut buf).unwrap_err();
2357    }
2358
2359    #[test]
2360    fn common_prefix() {
2361        use super::common_prefix as cp;
2362        assert_eq!(cp("", ""), 0);
2363        assert_eq!(cp("a", ""), 0);
2364        assert_eq!(cp("", "a"), 0);
2365        assert_eq!(cp("a", "a"), 1);
2366        assert_eq!(cp("aa", "a"), 1);
2367        assert_eq!(cp("a", "aa"), 1);
2368        assert_eq!(cp("ac", "ab"), 1);
2369    }
2370
2371    /// A certificate was mangled turning -- into n-dash, --- into
2372    /// m-dash.  Fun with Unicode.
2373    #[test]
2374    fn issue_610() {
2375        let mut buf = Vec::new();
2376        // First, we now accept any dash character, not only '-'.
2377        let mut reader = Reader::from_bytes(
2378            crate::tests::file("armor/test-3.unicode-dashes.asc"), None);
2379        reader.read_to_end(&mut buf).unwrap();
2380
2381        // Second, the transformation changed the number of dashes.
2382        let mut reader = Reader::from_bytes(
2383            crate::tests::file("armor/test-3.unbalanced-dashes.asc"), None);
2384        reader.read_to_end(&mut buf).unwrap();
2385
2386        // Third, as it is not about the dashes, we even accept none.
2387        let mut reader = Reader::from_bytes(
2388            crate::tests::file("armor/test-3.no-dashes.asc"), None);
2389        reader.read_to_end(&mut buf).unwrap();
2390    }
2391
2392    /// Tests the transformation of a cleartext signed message into a
2393    /// signed message.
2394    ///
2395    /// This test is merely concerned with the transformation, not
2396    /// with the signature verification.
2397    #[test]
2398    fn cleartext_signed_message() -> crate::Result<()> {
2399        use crate::{
2400            Packet,
2401            parse::Parse,
2402            types::HashAlgorithm,
2403        };
2404
2405        fn f<R>(clearsig: &[u8], reference: R, hash: HashAlgorithm)
2406                -> crate::Result<()>
2407        where R: AsRef<[u8]>
2408        {
2409            let mut reader = Reader::from_cookie_reader_csft(
2410                Box::new(buffered_reader::Memory::with_cookie(
2411                    clearsig, Default::default())),
2412                None, Default::default(), true);
2413
2414            let mut buf = Vec::new();
2415            reader.read_to_end(&mut buf)?;
2416
2417            let message = crate::Message::from_bytes(&buf)?;
2418            assert_eq!(message.packets().children().count(), 3);
2419
2420            // First, an one-pass-signature packet.
2421            if let Some(Packet::OnePassSig(ops)) =
2422                message.packets().path_ref(&[0])
2423            {
2424                assert_eq!(ops.hash_algo(), hash);
2425            } else {
2426                panic!("expected an OPS packet");
2427            }
2428
2429            // A literal packet.
2430            assert_eq!(message.body().unwrap().body(), reference.as_ref());
2431
2432            // And, the signature.
2433            if let Some(Packet::Signature(sig)) =
2434                message.packets().path_ref(&[2])
2435            {
2436                assert_eq!(sig.hash_algo(), hash);
2437            } else {
2438                panic!("expected an signature packet");
2439            }
2440
2441            // If we parse it without enabling the CSF transformation,
2442            // we should only find the signature.
2443            let mut reader = Reader::from_cookie_reader_csft(
2444                Box::new(buffered_reader::Memory::with_cookie(
2445                    clearsig, Default::default())),
2446                None, Default::default(), false);
2447
2448            let mut buf = Vec::new();
2449            reader.read_to_end(&mut buf)?;
2450
2451            let pp = crate::PacketPile::from_bytes(&buf)?;
2452            assert_eq!(pp.children().count(), 1);
2453
2454            // The signature.
2455            if let Some(Packet::Signature(sig)) = pp.path_ref(&[0]) {
2456                assert_eq!(sig.hash_algo(), hash);
2457            } else {
2458                panic!("expected an signature packet");
2459            }
2460            Ok(())
2461        }
2462
2463        f(crate::tests::message("a-problematic-poem.txt.cleartext.sig"),
2464          {
2465              // The test vector, created by GnuPG, does not preserve
2466              // the final newline.
2467              let mut reference =
2468                  crate::tests::message("a-problematic-poem.txt").to_vec();
2469              assert_eq!(reference.pop(), Some(b'\n'));
2470              reference
2471          }, HashAlgorithm::SHA256)?;
2472        f(crate::tests::file("crypto-refresh/cleartext-signed-message.txt"),
2473          crate::tests::file("crypto-refresh/cleartext-signed-message.txt.plain"),
2474          HashAlgorithm::SHA512)?;
2475        Ok(())
2476    }
2477}