diff options
-rw-r--r-- | ffi/include/sequoia/openpgp.h | 14 | ||||
-rw-r--r-- | ffi/src/openpgp.rs | 34 | ||||
-rw-r--r-- | net/src/async.rs | 2 | ||||
-rw-r--r-- | net/tests/hkp.rs | 6 | ||||
-rw-r--r-- | openpgp/src/armor.rs | 120 | ||||
-rw-r--r-- | openpgp/src/autocrypt.rs | 5 | ||||
-rw-r--r-- | openpgp/src/parse/parse.rs | 3 | ||||
-rw-r--r-- | openpgp/src/reader.rs | 2 | ||||
-rw-r--r-- | openpgp/src/tpk/mod.rs | 3 | ||||
-rw-r--r-- | tool/src/sq.rs | 2 |
10 files changed, 100 insertions, 91 deletions
diff --git a/ffi/include/sequoia/openpgp.h b/ffi/include/sequoia/openpgp.h index d4027ed0..dd19dae5 100644 --- a/ffi/include/sequoia/openpgp.h +++ b/ffi/include/sequoia/openpgp.h @@ -121,6 +121,11 @@ int sq_fingerprint_equal (const sq_fingerprint_t a, const sq_fingerprint_t b); /*/ typedef enum sq_armor_kind { /*/ + /// When reading an Armored file, accept any type. + /*/ + SQ_ARMOR_KIND_ANY, + + /*/ /// A generic OpenPGP message. /*/ SQ_ARMOR_KIND_MESSAGE, @@ -145,11 +150,6 @@ typedef enum sq_armor_kind { /*/ SQ_ARMOR_KIND_FILE, - /*/ - /// When reading an Armored file, accept any type. - /*/ - SQ_ARMOR_KIND_ANY, - /* Dummy value to make sure the enumeration has a defined size. Do not use this value. */ SQ_ARMOR_KIND_FORCE_WIDTH = INT_MAX, @@ -188,7 +188,9 @@ sq_reader_t sq_armor_reader_from_bytes (const uint8_t *b, size_t len, /*/ /// Returns the kind of data this reader is for. /// -/// Useful in combination with `Kind::Any`. +/// Useful if the kind of data is not known in advance. If the header +/// has not been encountered yet (try reading some data first!), this +/// function returns SQ_ARMOR_KIND_ANY. /*/ sq_armor_kind_t sq_armor_reader_kind (sq_reader_t reader); diff --git a/ffi/src/openpgp.rs b/ffi/src/openpgp.rs index a4866b16..5b6f773f 100644 --- a/ffi/src/openpgp.rs +++ b/ffi/src/openpgp.rs @@ -214,26 +214,26 @@ pub struct ArmorHeader { value: *const c_char, } -fn int_to_kind(kind: c_int) -> armor::Kind { +fn int_to_kind(kind: c_int) -> Option<armor::Kind> { match kind { - 0 => armor::Kind::Message, - 1 => armor::Kind::PublicKey, - 2 => armor::Kind::SecretKey, - 3 => armor::Kind::Signature, - 4 => armor::Kind::File, - 5 => armor::Kind::Any, + 0 => None, + 1 => Some(armor::Kind::Message), + 2 => Some(armor::Kind::PublicKey), + 3 => Some(armor::Kind::SecretKey), + 4 => Some(armor::Kind::Signature), + 5 => Some(armor::Kind::File), _ => panic!("Bad kind: {}", kind), } } -fn kind_to_int(kind: armor::Kind) -> c_int { +fn kind_to_int(kind: Option<armor::Kind>) -> c_int { match kind { - armor::Kind::Message => 0, - armor::Kind::PublicKey => 1, - armor::Kind::SecretKey => 2, - armor::Kind::Signature => 3, - armor::Kind::File => 4, - armor::Kind::Any => 5, + None => 0, + Some(armor::Kind::Message) => 1, + Some(armor::Kind::PublicKey) => 2, + Some(armor::Kind::SecretKey) => 3, + Some(armor::Kind::Signature) => 4, + Some(armor::Kind::File) => 5, } } @@ -364,7 +364,9 @@ pub extern "system" fn sq_armor_reader_from_bytes(b: *const uint8_t, len: size_t /// Returns the kind of data this reader is for. /// -/// Useful in combination with `Kind::Any`. +/// Useful if the kind of data is not known in advance. If the header +/// has not been encountered yet (try reading some data first!), this +/// function returns SQ_ARMOR_KIND_ANY. /// /// # Example /// @@ -549,7 +551,7 @@ pub extern "system" fn sq_armor_writer_new { let ctx = ctx.expect("Context is NULL"); let inner = inner.expect("Inner is NULL"); - let kind = int_to_kind(kind); + let kind = int_to_kind(kind).expect("KIND must not be SQ_ARMOR_KIND_ANY"); let mut header_ = Vec::new(); if header_len > 0 { diff --git a/net/src/async.rs b/net/src/async.rs index 7af6f2ae..77ec00bc 100644 --- a/net/src/async.rs +++ b/net/src/async.rs @@ -130,7 +130,7 @@ impl KeyServer { StatusCode::OK => { let c = Cursor::new(body.as_ref()); let r = armor::Reader::new( - c, armor::Kind::PublicKey); + c, Some(armor::Kind::PublicKey)); future::done(TPK::from_reader(r)) }, StatusCode::NOT_FOUND => diff --git a/net/tests/hkp.rs b/net/tests/hkp.rs index 4acbf56d..cbb86532 100644 --- a/net/tests/hkp.rs +++ b/net/tests/hkp.rs @@ -22,7 +22,7 @@ extern crate openpgp; extern crate sequoia_core; extern crate sequoia_net; -use openpgp::armor::{Reader, Kind}; +use openpgp::armor::Reader; use openpgp::TPK; use openpgp::{Fingerprint, KeyID}; use sequoia_core::{Context, NetworkPolicy}; @@ -92,7 +92,7 @@ fn service(req: Request<Body>) "keytext" => { let key = TPK::from_reader( Reader::new(Cursor::new(value.into_owned()), - Kind::Any)).unwrap(); + None)).unwrap(); assert_eq!( key.fingerprint(), Fingerprint::from_hex(FP) @@ -171,6 +171,6 @@ fn send() { let mut keyserver = KeyServer::new(&ctx, &format!("hkp://{}", addr)).unwrap(); let key = TPK::from_reader(Reader::new(Cursor::new(RESPONSE), - Kind::Any)).unwrap(); + None)).unwrap(); keyserver.send(&key).unwrap(); } diff --git a/openpgp/src/armor.rs b/openpgp/src/armor.rs index 7cfb599e..166391aa 100644 --- a/openpgp/src/armor.rs +++ b/openpgp/src/armor.rs @@ -21,7 +21,7 @@ //! use openpgp::armor::{Reader, Kind}; //! //! let mut file = File::open("somefile.asc").unwrap(); -//! let mut r = Reader::new(&mut file, Kind::File); +//! let mut r = Reader::new(&mut file, Some(Kind::File)); //! ``` extern crate base64; @@ -61,8 +61,6 @@ pub enum Kind { Signature, /// A generic file. This is a GnuPG extension. File, - /// When reading an Armored file, accept any type. - Any, } impl Arbitrary for Kind { @@ -111,7 +109,6 @@ impl Kind { &Kind::SecretKey => "PRIVATE KEY BLOCK", &Kind::Signature => "SIGNATURE", &Kind::File => "ARMORED FILE", - &Kind::Any => unreachable!(), } } @@ -176,7 +173,6 @@ impl<W: Write> Writer<W> { /// # } /// ``` pub fn new(inner: W, kind: Kind, headers: &[(&str, &str)]) -> Result<Self> { - assert!(kind != Kind::Any); let mut w = Writer { sink: inner, kind: kind, @@ -326,7 +322,7 @@ impl<W: Write> Drop for Writer<W> { /// as the line the header is in is only prefixed by whitespace. pub struct Reader<'a> { source: Box<'a + BufferedReader<()>>, - kind: Kind, + kind: Option<Kind>, buffer: Vec<u8>, crc: CRC, expect_crc: Option<u32>, @@ -355,16 +351,16 @@ impl<'a> Reader<'a> { /// -----END PGP ARMORED FILE-----"; /// /// let mut cursor = io::Cursor::new(&data); - /// let mut reader = Reader::new(&mut cursor, Kind::Any); + /// let mut reader = Reader::new(&mut cursor, None); /// /// let mut content = String::new(); /// reader.read_to_string(&mut content)?; /// assert_eq!(content, "Hello world!"); - /// assert_eq!(reader.kind(), Kind::File); + /// assert_eq!(reader.kind(), Some(Kind::File)); /// # Ok(()) /// # } /// ``` - pub fn new<R>(inner: R, kind: Kind) -> Self + pub fn new<R>(inner: R, kind: Option<Kind>) -> Self where R: 'a + Read { Self::from_buffered_reader( @@ -373,7 +369,7 @@ impl<'a> Reader<'a> { } /// Creates a `Reader` from an `io::Read`er. - pub fn from_reader<R>(reader: R, kind: Kind) -> Self + pub fn from_reader<R>(reader: R, kind: Option<Kind>) -> Self where R: 'a + Read { Self::from_buffered_reader( @@ -382,7 +378,7 @@ impl<'a> Reader<'a> { } /// Creates a `Reader` from a file. - pub fn from_file<P>(path: P, kind: Kind) -> Result<Self> + pub fn from_file<P>(path: P, kind: Option<Kind>) -> Result<Self> where P: AsRef<Path> { Ok(Self::from_buffered_reader( @@ -391,14 +387,14 @@ impl<'a> Reader<'a> { } /// Creates a `Reader` from a buffer. - pub fn from_bytes(bytes: &'a [u8], kind: Kind) -> Self { + pub fn from_bytes(bytes: &'a [u8], kind: Option<Kind>) -> Self { Self::from_buffered_reader( Box::new(BufferedReaderMemory::new(bytes)), kind) } pub(crate) fn from_buffered_reader(inner: Box<'a + BufferedReader<()>>, - kind: Kind) -> Self { + kind: Option<Kind>) -> Self { Reader { source: Box::new(BufferedReaderGeneric::new(inner, None)), kind: kind, @@ -413,8 +409,10 @@ impl<'a> Reader<'a> { /// Returns the kind of data this reader is for. /// - /// Useful in combination with `Kind::Any`. - pub fn kind(&self) -> Kind { + /// Useful if the kind of data is not known in advance. If the + /// header has not been encountered yet (try reading some data + /// first!), this function returns None. + pub fn kind(&self) -> Option<Kind> { self.kind } @@ -444,13 +442,13 @@ impl<'a> Reader<'a> { for i in 0..(line.len() - 27 + 1) { if let Some(kind) = Kind::detect(&line[i..]) { - if self.kind == Kind::Any { + if self.kind == None { // Found any! - self.kind = kind; + self.kind = Some(kind); break 'search; } - if self.kind == kind { + if self.kind == Some(kind) { // Found it! break 'search; } @@ -515,7 +513,7 @@ impl<'a> Reader<'a> { } /// Parses the footer. - fn finalize(footer: &[u8], kind: Kind) -> Result<Option<u32>> { + fn finalize(footer: &[u8], kind: Option<Kind>) -> Result<Option<u32>> { let mut off = 0; /* Look for CRC. The CRC is optional. */ @@ -545,8 +543,10 @@ impl<'a> Reader<'a> { None }; - if ! footer[off..].starts_with(&kind.end().into_bytes()) { - return Err(Error::new(ErrorKind::InvalidInput, "Invalid ASCII Armor footer.")); + if let Some(kind) = kind { + if ! footer[off..].starts_with(&kind.end().into_bytes()) { + return Err(Error::new(ErrorKind::InvalidInput, "Invalid ASCII Armor footer.")); + } } Ok(crc) @@ -654,7 +654,7 @@ impl<'a> Read for Reader<'a> { // Later, we may have to get some more until we have a // multiple of four non-whitespace ASCII characters. let mut want = (buf.len() - read + 2) / 3 * 4 - + self.kind.footer_max_len(); + + self.kind.map(|k| k.footer_max_len()).unwrap_or(46); // Keep track of how much we got last time to detect // hitting EOF. @@ -670,28 +670,31 @@ impl<'a> Read for Reader<'a> { } // Check if we see the footer. If so, we're almost done. - if let Some((n, end)) = find_footer(&raw, self.kind) { - self.expect_crc = Reader::finalize(&raw[n..], self.kind)?; - self.finalized = true; - match base64::decode_config(&raw[..n], base64::MIME) { - Ok(d) => break (end, d), - Err(e) => - return Err(Error::new(ErrorKind::InvalidInput, e)), - } - } else { - let n = &raw.iter().filter( - |c| ! (**c).is_ascii_whitespace()).count(); - if n % 4 == 0 { - // Success, try to decode it. - match base64::decode_config(&raw, base64::MIME) { - Ok(d) => break (raw.len(), d), - Err(e) => return Err(Error::new(ErrorKind::InvalidInput, e)), + if let Some(kind) = self.kind { + if let Some((n, end)) = find_footer(&raw, kind) { + self.expect_crc = Reader::finalize(&raw[n..], self.kind)?; + self.finalized = true; + match base64::decode_config(&raw[..n], base64::MIME) { + Ok(d) => break (end, d), + Err(e) => + return Err(Error::new(ErrorKind::InvalidInput, e)), } } + } - // Get some more bytes. - want = got + 4 - n % 4; + // See how many non-whitespace characters we got. + let n = &raw.iter().filter( + |c| ! (**c).is_ascii_whitespace()).count(); + if n % 4 == 0 { + // Enough! Try to decode them. + match base64::decode_config(&raw, base64::MIME) { + Ok(d) => break (raw.len(), d), + Err(e) => return Err(Error::new(ErrorKind::InvalidInput, e)), + } } + + // Otherwise, get some more bytes. + want = got + 4 - n % 4; } }; self.source.consume(consumed); @@ -754,8 +757,7 @@ impl<'a> Read for Reader<'a> { macro_rules! armored { ($data:expr) => {{ use ::std::io::Cursor; - $crate::armor::Reader::new(Cursor::new(&$data), - $crate::armor::Kind::Any) + $crate::armor::Reader::new(Cursor::new(&$data), None) }}; } @@ -875,7 +877,7 @@ mod test { fn dearmor_binary() { for len in TEST_VECTORS.iter() { let mut file = File::open(format!("tests/data/armor/test-{}.bin", len)).unwrap(); - let mut r = Reader::new(&mut file, Kind::Message); + let mut r = Reader::new(&mut file, Some(Kind::Message)); let mut buf = [0; 5]; let e = r.read(&mut buf); assert!(e.is_err()); @@ -885,7 +887,7 @@ mod test { #[test] fn dearmor_wrong_kind() { let mut file = File::open("tests/data/armor/test-0.asc").unwrap(); - let mut r = Reader::new(&mut file, Kind::Message); + let mut r = Reader::new(&mut file, Some(Kind::Message)); let mut buf = [0; 5]; let e = r.read(&mut buf); assert!(e.is_err()); @@ -894,7 +896,7 @@ mod test { #[test] fn dearmor_wrong_crc() { let mut file = File::open("tests/data/armor/test-0.bad-crc.asc").unwrap(); - let mut r = Reader::new(&mut file, Kind::File); + let mut r = Reader::new(&mut file, Some(Kind::File)); let mut buf = [0; 5]; let e = r.read(&mut buf); assert!(e.is_err()); @@ -903,7 +905,7 @@ mod test { #[test] fn dearmor_wrong_footer() { let mut file = File::open("tests/data/armor/test-2.bad-footer.asc").unwrap(); - let mut r = Reader::new(&mut file, Kind::File); + let mut r = Reader::new(&mut file, Some(Kind::File)); let mut buf = [0; 5]; let e = r.read(&mut buf); assert!(e.is_err()); @@ -912,7 +914,7 @@ mod test { #[test] fn dearmor_no_crc() { let mut file = File::open("tests/data/armor/test-1.no-crc.asc").unwrap(); - let mut r = Reader::new(&mut file, Kind::File); + let mut r = Reader::new(&mut file, Some(Kind::File)); let mut buf = [0; 5]; let e = r.read(&mut buf); assert!(e.unwrap() == 1 && buf[0] == 0xde); @@ -921,7 +923,7 @@ mod test { #[test] fn dearmor_with_header() { let mut file = File::open("tests/data/armor/test-3.with-headers.asc").unwrap(); - let mut r = Reader::new(&mut file, Kind::File); + let mut r = Reader::new(&mut file, Some(Kind::File)); assert_eq!(r.headers().unwrap(), &[("Comment".into(), "Some Header".into()), ("Comment".into(), "Another one".into())]); @@ -933,10 +935,10 @@ mod test { #[test] fn dearmor_any() { let mut file = File::open("tests/data/armor/test-3.with-headers.asc").unwrap(); - let mut r = Reader::new(&mut file, Kind::Any); + let mut r = Reader::new(&mut file, None); let mut buf = [0; 5]; let e = r.read(&mut buf); - assert!(r.kind() == Kind::File); + assert!(r.kind() == Some(Kind::File)); assert!(e.is_ok()); } @@ -956,10 +958,10 @@ mod test { write!(&mut garbage, "Some\ngarbage\nlines\n\t\r ").unwrap(); garbage.extend_from_slice(&armored); - let mut r = Reader::new(Cursor::new(&garbage), Kind::Any); + let mut r = Reader::new(Cursor::new(&garbage), None); let mut buf = [0; 5]; let e = r.read(&mut buf); - assert!(r.kind() == Kind::File); + assert!(r.kind() == Some(Kind::File)); assert!(e.is_ok()); // Again, but this time add a non-whitespace character in the @@ -968,7 +970,7 @@ mod test { write!(&mut garbage, "Some\ngarbage\nlines\n\t.\r ").unwrap(); garbage.extend_from_slice(&armored); - let mut r = Reader::new(Cursor::new(&garbage), Kind::Any); + let mut r = Reader::new(Cursor::new(&garbage), None); let mut buf = [0; 5]; let e = r.read(&mut buf); assert!(e.is_err()); @@ -982,7 +984,7 @@ mod test { file.read_to_end(&mut bin).unwrap(); let mut file = File::open(format!("tests/data/armor/test-{}.asc", len)).unwrap(); - let mut r = Reader::new(&mut file, Kind::File); + let mut r = Reader::new(&mut file, Some(Kind::File)); let mut dearmored = Vec::<u8>::new(); r.read_to_end(&mut dearmored).unwrap(); @@ -998,7 +1000,7 @@ mod test { file.read_to_end(&mut bin).unwrap(); let mut file = File::open(format!("tests/data/armor/test-{}.asc", len)).unwrap(); - let r = Reader::new(&mut file, Kind::File); + let r = Reader::new(&mut file, Some(Kind::File)); let mut dearmored = Vec::<u8>::new(); for c in r.bytes() { dearmored.push(c.unwrap()); @@ -1013,14 +1015,14 @@ mod test { let mut file = File::open("tests/data/keys/yuge-key-so-yuge-the-yugest.asc") .unwrap(); - let mut r = Reader::new(&mut file, Kind::Any); + let mut r = Reader::new(&mut file, None); let mut dearmored = Vec::<u8>::new(); r.read_to_end(&mut dearmored).unwrap(); let mut file = File::open("tests/data/keys/yuge-key-so-yuge-the-yugest.asc") .unwrap(); - let r = Reader::new(&mut file, Kind::Any); + let r = Reader::new(&mut file, None); let mut dearmored = Vec::<u8>::new(); for c in r.bytes() { dearmored.push(c.unwrap()); @@ -1037,12 +1039,12 @@ mod test { .unwrap(); let mut recovered = Vec::new(); - Reader::new(Cursor::new(&encoded), kind) + Reader::new(Cursor::new(&encoded), Some(kind)) .read_to_end(&mut recovered) .unwrap(); let mut recovered_any = Vec::new(); - Reader::new(Cursor::new(&encoded), Kind::Any) + Reader::new(Cursor::new(&encoded), None) .read_to_end(&mut recovered_any) .unwrap(); diff --git a/openpgp/src/autocrypt.rs b/openpgp/src/autocrypt.rs index 5cfdf9ad..73d982bb 100644 --- a/openpgp/src/autocrypt.rs +++ b/openpgp/src/autocrypt.rs @@ -422,7 +422,7 @@ impl AutocryptSetupMessage { -> Result<AutocryptSetupMessageParser<'a>> { // The outer message uses ASCII-armor. It includes a password // hint. Hence, we need to parse it aggressively. - let mut r = armor::Reader::new(r, armor::Kind::Message); + let mut r = armor::Reader::new(r, Some(armor::Kind::Message)); // Note, it is essential that we call r.headers here so that // we can return any error now and not in @@ -604,7 +604,8 @@ impl<'a> AutocryptSetupMessageParser<'a> { // The inner message consists of an ASCII-armored encoded // TSK. let (prefer_encrypt, tsk) = { - let mut r = armor::Reader::new(&mut pp, armor::Kind::SecretKey); + let mut r = armor::Reader::new(&mut pp, + Some(armor::Kind::SecretKey)); let prefer_encrypt = { let headers = r.headers()?; diff --git a/openpgp/src/parse/parse.rs b/openpgp/src/parse/parse.rs index 95f706d7..0f4240dc 100644 --- a/openpgp/src/parse/parse.rs +++ b/openpgp/src/parse/parse.rs @@ -3154,7 +3154,8 @@ mod test { // The following TPK is corrupted about a third the way // through. Make sure we can recover. let mut ppr = PacketParser::from_reader( - Reader::from_bytes(bytes!("../keys/corrupted.pgp"), Kind::PublicKey)) + Reader::from_bytes(bytes!("../keys/corrupted.pgp"), + Some(Kind::PublicKey))) .unwrap(); let mut sigs = 0; diff --git a/openpgp/src/reader.rs b/openpgp/src/reader.rs index 0406e6c3..dd84132d 100644 --- a/openpgp/src/reader.rs +++ b/openpgp/src/reader.rs @@ -22,7 +22,7 @@ impl<'a> Reader<'a> { Ok(Reader(br)) } else { Ok(Reader(Box::new(BufferedReaderGeneric::new( - armor::Reader::from_buffered_reader(br, armor::Kind::Any), + armor::Reader::from_buffered_reader(br, None), None)))) } } diff --git a/openpgp/src/tpk/mod.rs b/openpgp/src/tpk/mod.rs index c9c92fad..497ffc2b 100644 --- a/openpgp/src/tpk/mod.rs +++ b/openpgp/src/tpk/mod.rs @@ -2035,7 +2035,8 @@ mod test { cur.set_position(0); - let r = armor::Reader::from_reader(&mut cur, armor::Kind::SecretKey); + let r = armor::Reader::from_reader(&mut cur, + Some(armor::Kind::SecretKey)); let t2 = TPK::from_reader(r).unwrap(); assert_eq!(t1.tpk().fingerprint(), t2.fingerprint()); diff --git a/tool/src/sq.rs b/tool/src/sq.rs index 353a6574..2d0b3411 100644 --- a/tool/src/sq.rs +++ b/tool/src/sq.rs @@ -101,7 +101,7 @@ fn real_main() -> Result<(), failure::Error> { ("dearmor", Some(m)) => { let mut input = open_or_stdin(m.value_of("input"))?; let mut output = create_or_stdout(m.value_of("output"))?; - let mut filter = armor::Reader::new(&mut input, armor::Kind::Any); + let mut filter = armor::Reader::new(&mut input, None); io::copy(&mut filter, &mut output)?; }, ("autocrypt", Some(m)) => { |