1use 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
61const TRACE: bool = false;
63
64pub(crate) const LINE_LENGTH: usize = 64;
70
71const LINE_ENDING: &str = "\n";
72
73#[derive(Copy, Clone, Debug, PartialEq)]
77#[non_exhaustive]
78pub enum Kind {
79 Message,
83 PublicKey,
85 SecretKey,
87 Signature,
89 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#[derive(Clone, Copy, Debug, PartialEq, Eq)]
116enum Label {
117 Message,
121 PublicKey,
123 SecretKey,
125 Signature,
127 CleartextSignature,
133 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 fn detect_header(blurb: &[u8]) -> Option<(Self, usize)> {
157 let (leading_dashes, rest) = dash_prefix(blurb);
158
159 if ! rest.starts_with(b"BEGIN PGP ") {
161 return None;
162 }
163 let rest = &rest[b"BEGIN PGP ".len()..];
164
165 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 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 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
245pub 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 pub fn new(inner: W, kind: Kind) -> Result<Self> {
285 Self::with_headers(inner, kind, Option::<(&str, &str)>::None)
286 }
287
288 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 write!(&mut cur, "{}", LINE_ENDING)?;
343 }
344
345 Ok(w)
346 }
347
348 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 pub fn get_ref(&self) -> &W {
392 &self.sink
393 }
394
395 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 crate::vec_truncate(&mut self.header, 0);
406 self.header.shrink_to_fit();
407 }
408 Ok(())
409 }
410
411 pub fn finalize(mut self) -> Result<W> {
415 if ! self.dirty {
416 return Ok(self.sink);
418 }
419 self.finalize_armor()?;
420 Ok(self.sink)
421 }
422
423 fn finalize_armor(&mut self) -> Result<()> {
425 if ! self.dirty {
426 return Ok(());
428 }
429 self.finalize_headers()?;
430
431 if !self.stash.is_empty() {
433 self.sink.write_all(base64std.encode(&self.stash).as_bytes())?;
434 self.column += 4;
435 }
436
437 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 let crc = self.crc.finalize();
457 let bytes = &crc.to_be_bytes()[1..4];
458
459 write!(self.sink, "={}{}",
461 base64nopad.encode(&bytes), LINE_ENDING)?;
462 },
463
464 Some(Profile::RFC9580) => (),
465 }
466
467 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 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 self.crc.update(buf);
495 },
496
497 Some(Profile::RFC9580) => (),
498 }
499
500 let mut input = buf;
501 let mut written = 0;
502
503 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 return Ok(written);
517 }
518 assert_eq!(self.stash.len(), 3);
519
520 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 let n_blocks = input.len() / 3;
531 let input_bytes = n_blocks * 3;
532 if input_bytes > 0 {
533 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 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#[derive(Debug, Clone, Copy, PartialEq)]
572#[non_exhaustive]
573pub enum ReaderMode {
574 Tolerant(Option<Kind>),
586
587 VeryTolerant,
600}
601assert_send_and_sync!(ReaderMode);
602
603#[derive(Debug)]
605pub struct Reader<'a> {
606 buffer: Option<Vec<u8>>,
615 unused_buffer: Option<Vec<u8>>,
617 cursor: usize,
619 preferred_chunk_size: usize,
621 source: Box<dyn BufferedReader<Cookie> + 'a>,
623 error: Option<Error>,
625 eof: bool,
627 cookie: Cookie,
629 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 enable_csft: bool,
643
644 csft: Option<CSFTransformer>,
646}
647assert_send_and_sync!(Reader<'_>);
648
649const 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#[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 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 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 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 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 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 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 pub fn kind(&self) -> Option<Kind> {
840 self.kind
841 }
842
843 pub fn headers(&mut self) -> Result<&[(String, String)]> {
880 self.initialize()?;
881 Ok(&self.headers[..])
882 }
883}
884
885impl<'a> Reader<'a> {
886 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 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 let mut b = [0; 4]; for d in dashes() {
928 d.encode_utf8(&mut b);
929 valid_start.push(b[0]);
930 }
931
932 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 let mut b = [0; 4]; for d in dashes() {
953 d.encode_utf8(&mut b);
954 valid_start.push(b[0]);
955 }
956
957 valid_start.push(b'B');
959
960 valid_start.sort_unstable();
961 valid_start.dedup();
962 valid_start
963 })
964 }
965
966 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 self.source.drop_through(&[b'\n'], true)?;
981 crate::vec_truncate(&mut prefix, 0);
982 }
983 lines += 1;
984
985 while matches!(self.source.data_hard(1)?[0],
987 b' ' | b'\t' | b'\r' | b'\n' |
989 b'>' | b'|' | b']' | b'}' )
991 {
992 let c = self.source.data(1)?[0];
993 if c == b'\n' {
994 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 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 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 continue 'search;
1033 }
1034
1035 if label == Label::CleartextSignature && self.enable_csft
1036 {
1037 self.csft = Some(CSFTransformer::default());
1039
1040 self.cookie.set_processing_csf_message();
1047
1048 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 self.kind = Some(kind);
1063 break 'search len;
1064 }
1065
1066 if expected_kind == Some(kind) {
1067 self.kind = Some(kind);
1069 break 'search len;
1070 }
1071 }
1072
1073 if self.mode == ReaderMode::VeryTolerant {
1074 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 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 fn read_headers(&mut self) -> Result<()> {
1101 tracer!(TRACE, "armor::Reader::read_headers");
1102 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 self.prefix.iter().all(|b| (*b as char).is_ascii_whitespace()) {
1124 crate::vec_truncate(&mut self.prefix, 0);
1125 } else {
1126 return Err(
1128 Error::new(ErrorKind::InvalidInput,
1129 "Inconsistent quoting of armored data"));
1130 }
1131 }
1132
1133 let mut n = 0;
1135 let mut prefix_len = None;
1138 let mut lines = 0;
1139 loop {
1140 self.source.consume(
1147 prefix_len.take().unwrap_or_else(|| self.prefix.len()));
1148
1149 self.source.consume(n);
1150
1151 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 if line.is_err() {
1160 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 let line = if let Some(rest) = line.strip_suffix("\r\n") {
1180 rest
1182 } else if let Some(rest) = line.strip_suffix('\n') {
1183 rest
1185 } else {
1186 line
1188 };
1189
1190 let key_value = line.splitn(2, ": ").collect::<Vec<&str>>();
1192 if key_value.len() == 1 {
1193 if line.trim_start().is_empty() {
1194 break;
1196 } else if lines == 1 {
1197 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 let next_prefix =
1214 &self.source.data_hard(n + self.prefix.len())?
1215 [n..n + self.prefix.len()];
1216
1217 let l = common_prefix(&self.prefix, next_prefix);
1219 let full_prefix = l == self.prefix.len();
1220 if ! (full_prefix
1221 || 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 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
1243fn 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 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 const THRESHOLD : usize = 64;
1287
1288 let to_read =
1289 cmp::max(
1290 THRESHOLD + 2,
1292
1293 base64_size(buf.len())
1296 + 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 cmp::max(THRESHOLD, buf.len() / 3 * 4),
1313 self.prefix_remaining,
1314 self.prefix.len());
1315
1316 assert_eq!(base64data.len() % 4, 0);
1318
1319 let decoded = if base64data.len() / 4 * 3 > buf.len() {
1320 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 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 let consumed = {
1350 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 5
1370 } else {
1371 0
1372 }
1373 };
1374 self.source.consume(consumed);
1375
1376 self.source.data_consume_hard(self.prefix.len())?;
1378 let consumed = {
1380 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 let Some(kind) = self.kind {
1389 let footer_lookahead = 128; 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 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 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 break;
1441 }
1442
1443 let n = prefixed_line.len().min(self.prefix.len());
1446 let prefix = &prefixed_line[..n];
1447 let mut line = &prefixed_line[n..];
1448
1449 let l = common_prefix(&self.prefix, prefix);
1451 let full_prefix = l == self.prefix.len();
1452 if ! (full_prefix
1453 || 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 && rest.starts_with(b"BEGIN PGP SIGNATURE")
1467 {
1468 let l = prefixed_line.len();
1472 self.source.consume(l);
1473 break;
1474 }
1475
1476 if line.starts_with(b"- ") {
1478 line = &line[2..];
1479 }
1480
1481 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 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 let l = prefixed_line.len();
1510 self.source.consume(l);
1511 }
1512
1513 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 let mut literal = Literal::new(DataFormat::Unicode);
1525 literal.set_body(text);
1526 literal
1527 };
1528
1529 self.csft = None;
1534
1535 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 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 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 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 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 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 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 assert!(self.cursor <= buffer.len());
1649 } else {
1650 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 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 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 self.error = Some(err);
1705 break;
1706 },
1707 }
1708 }
1709
1710 if amount_read > 0 {
1711 if let Some(ref buffer) = self.buffer {
1713 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 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 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
1850fn dashes() -> impl Iterator<Item = char> {
1852 ['\u{002D}', '\u{058A}', '\u{05BE}', '\u{1400}', '\u{1806}', '\u{2010}', '\u{2011}', '\u{2012}', '\u{2013}', '\u{2014}', '\u{2015}', '\u{2E17}', '\u{2E1A}', '\u{2E3A}', '\u{2E3B}', '\u{2E40}', '\u{301C}', '\u{3030}', '\u{30A0}', '\u{FE31}', '\u{FE32}', '\u{FE58}', '\u{FE63}', '\u{FF0D}', ].iter().cloned()
1877}
1878
1879fn dash_prefix(d: &[u8]) -> (&[u8], &[u8]) {
1884 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 match c {
1895 '\u{002D}' | '\u{058A}' | '\u{05BE}' | '\u{1400}' | '\u{1806}' | '\u{2010}' | '\u{2011}' | '\u{2012}' | '\u{2013}' | '\u{2014}' | '\u{2015}' | '\u{2E17}' | '\u{2E1A}' | '\u{2E3A}' | '\u{2E3B}' | '\u{2E40}' | '\u{301C}' | '\u{3030}' | '\u{30A0}' | '\u{FE31}' | '\u{FE32}' | '\u{FE58}' | '\u{FE63}' | '\u{FF0D}' => 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(); 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(); 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 assert!(Writer::new(Vec::new(), Kind::File).unwrap()
1997 .finalize().unwrap().is_empty());
1998
1999 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 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 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 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 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 #[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 #[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 reader.read_to_end(&mut buf).unwrap_err();
2313 }
2314
2315 #[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 reader.read_to_end(&mut buf).unwrap_err();
2341 }
2342
2343 #[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 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 #[test]
2374 fn issue_610() {
2375 let mut buf = Vec::new();
2376 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 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 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 #[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 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 assert_eq!(message.body().unwrap().body(), reference.as_ref());
2431
2432 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 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 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 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}