summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-10-20 15:47:14 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-10-20 16:42:17 +0200
commit8a38f0483e1bfb907f8aac7764a5094ca9068c44 (patch)
treed608b68166472606ca0b369a41680cbfb101b59b
parent14c3a12554fa8b5c46b3905162bd9f09695f6dc3 (diff)
openpgp: Support reading certificates from multiple armor blocks.
- Fixes #256.
-rw-r--r--openpgp/src/cert/parser/mod.rs48
1 files changed, 46 insertions, 2 deletions
diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs
index d4b0a6d5..bd16ead4 100644
--- a/openpgp/src/cert/parser/mod.rs
+++ b/openpgp/src/cert/parser/mod.rs
@@ -535,11 +535,36 @@ impl<'a> From<PacketParserResult<'a>> for CertParser<'a>
{
/// Initializes a `CertParser` from a `PacketParser`.
fn from(ppr: PacketParserResult<'a>) -> Self {
+ use std::io::ErrorKind::UnexpectedEof;
let mut parser : Self = Default::default();
if let PacketParserResult::Some(pp) = ppr {
let mut ppp : Box<Option<PacketParser>> = Box::new(Some(pp));
+ let mut retry_with_reader = Box::new(None);
parser.source = Some(
Box::new(std::iter::from_fn(move || {
+ if let Some(reader) = retry_with_reader.take() {
+ // Try to find the next (armored) blob.
+ match PacketParser::from_buffered_reader(reader) {
+ Ok(PacketParserResult::Some(pp)) => {
+ // We read at least one packet. Try
+ // to parse the next cert.
+ *ppp = Some(pp);
+ },
+ Ok(PacketParserResult::EOF(_)) =>
+ (), // No dice.
+ Err(err) => {
+ // See if we just reached the end.
+ if let Some(e) = err.downcast_ref::<io::Error>()
+ {
+ if e.kind() == UnexpectedEof {
+ return None;
+ }
+ }
+ return Some(Err(err));
+ },
+ }
+ }
+
if let Some(mut pp) = ppp.take() {
if let Packet::Unknown(_) = pp.packet {
// Buffer unknown packets. This may be a
@@ -552,8 +577,12 @@ impl<'a> From<PacketParserResult<'a>> for CertParser<'a>
match pp.next() {
Ok((packet, ppr)) => {
- if let PacketParserResult::Some(pp) = ppr {
- *ppp = Some(pp);
+ match ppr {
+ PacketParserResult::Some(pp) =>
+ *ppp = Some(pp),
+ PacketParserResult::EOF(eof) =>
+ *retry_with_reader =
+ Some(eof.into_reader()),
}
Some(Ok(packet))
},
@@ -1379,4 +1408,19 @@ mod test {
Ok(())
}
+
+ #[test]
+ fn concatenated_armored_certs() -> Result<()> {
+ let mut keyring = Vec::new();
+ keyring.extend_from_slice(b"some\ntext\n");
+ keyring.extend_from_slice(crate::tests::key("testy.asc"));
+ keyring.extend_from_slice(crate::tests::key("testy.asc"));
+ keyring.extend_from_slice(b"some\ntext\n");
+ keyring.extend_from_slice(crate::tests::key("testy.asc"));
+ keyring.extend_from_slice(b"some\ntext\n");
+ let certs = CertParser::from_bytes(&keyring)?.collect::<Vec<_>>();
+ assert_eq!(certs.len(), 3);
+ assert!(certs.iter().all(|c| c.is_ok()));
+ Ok(())
+ }
}