summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2019-08-30 16:12:06 +0200
committerNeal H. Walfield <neal@pep.foundation>2019-08-30 16:12:06 +0200
commit50d651a5f4045dccfcb2aec09bec44d5a92958f8 (patch)
tree662dea4a0ef8964cdde1f60a5e7b9b3307589a03
parentbeded916330c406982e244d1d71ebcf9a80514dd (diff)
openpgp: Move TPKParser to tpk::parser.
- Move the TPKParser structure and its implementation from the tpk module to the tpk::parser module.
-rw-r--r--openpgp/src/tpk/mod.rs423
-rw-r--r--openpgp/src/tpk/parser/mod.rs412
2 files changed, 423 insertions, 412 deletions
diff --git a/openpgp/src/tpk/mod.rs b/openpgp/src/tpk/mod.rs
index 983e66d6..fe33fee0 100644
--- a/openpgp/src/tpk/mod.rs
+++ b/openpgp/src/tpk/mod.rs
@@ -6,7 +6,6 @@ use std::path::Path;
use std::slice;
use std::mem;
use std::fmt;
-use std::vec;
use time;
use crate::{
@@ -17,7 +16,6 @@ use crate::{
SignatureType,
HashAlgorithm,
packet,
- packet::Tag,
packet::Signature,
packet::signature,
packet::Key,
@@ -45,16 +43,11 @@ pub use keyiter::KeyIter;
pub use parser::{
KeyringValidity,
KeyringValidator,
+ TPKParser,
TPKValidity,
TPKValidator,
};
-use parser::low_level::{
- Lexer,
- Token,
- TPKParser as TPKLowLevelParser,
-};
-
const TRACE : bool = false;
// Helper functions.
@@ -322,407 +315,6 @@ impl ComponentBinding<Unknown> {
}
}
-// A TPKParser can read packets from either an Iterator or a
-// PacketParser. Ideally, we would just take an iterator, but we
-// want to be able to handle errors, which iterators hide.
-enum PacketSource<'a, I: Iterator<Item=Packet>> {
- EOF,
- PacketParser(PacketParser<'a>),
- Iter(I),
-}
-
-/// An iterator over a sequence of TPKs (e.g., an OpenPGP keyring).
-///
-/// The source of packets can either be a `PacketParser` or an
-/// iterator over `Packet`s. (In the latter case, the underlying
-/// parser is not able to propagate errors. Thus, this is only
-/// appropriate for in-memory structures, like a vector of `Packet`s
-/// or a `PacketPile`.)
-///
-/// # Example
-///
-/// ```rust
-/// # extern crate sequoia_openpgp as openpgp;
-/// # use openpgp::Result;
-/// # use openpgp::parse::{Parse, PacketParserResult, PacketParser};
-/// use openpgp::tpk::TPKParser;
-///
-/// # fn main() { f().unwrap(); }
-/// # fn f() -> Result<()> {
-/// # let ppr = PacketParser::from_bytes(b"")?;
-/// for tpko in TPKParser::from_packet_parser(ppr) {
-/// match tpko {
-/// Ok(tpk) => {
-/// println!("Key: {}", tpk.primary().key());
-/// for binding in tpk.userids() {
-/// println!("User ID: {}", binding.userid());
-/// }
-/// }
-/// Err(err) => {
-/// eprintln!("Error reading keyring: {}", err);
-/// }
-/// }
-/// }
-/// # Ok(())
-/// # }
-/// ```
-pub struct TPKParser<'a, I: Iterator<Item=Packet>> {
- source: PacketSource<'a, I>,
- packets: Vec<Packet>,
- saw_error: bool,
- filter: Vec<Box<Fn(&TPK, bool) -> bool + 'a>>,
-}
-
-impl<'a, I: Iterator<Item=Packet>> Default for TPKParser<'a, I> {
- fn default() -> Self {
- TPKParser {
- source: PacketSource::EOF,
- packets: vec![],
- saw_error: false,
- filter: vec![],
- }
- }
-}
-
-// When using a `PacketParser`, we never use the `Iter` variant.
-// Nevertheless, we need to provide a concrete type.
-// vec::IntoIter<Packet> is about as good as any other.
-impl<'a> TPKParser<'a, vec::IntoIter<Packet>> {
- /// Initializes a `TPKParser` from a `PacketParser`.
- pub fn from_packet_parser(ppr: PacketParserResult<'a>) -> Self {
- let mut parser : Self = Default::default();
- if let PacketParserResult::Some(pp) = ppr {
- parser.source = PacketSource::PacketParser(pp);
- }
- parser
- }
-}
-
-impl<'a> Parse<'a, TPKParser<'a, vec::IntoIter<Packet>>>
- for TPKParser<'a, vec::IntoIter<Packet>>
-{
- /// Initializes a `TPKParser` from a `Read`er.
- fn from_reader<R: 'a + io::Read>(reader: R) -> Result<Self> {
- Ok(Self::from_packet_parser(PacketParser::from_reader(reader)?))
- }
-
- /// Initializes a `TPKParser` from a `File`.
- fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
- Ok(Self::from_packet_parser(PacketParser::from_file(path)?))
- }
-
- /// Initializes a `TPKParser` from a byte string.
- fn from_bytes(data: &'a [u8]) -> Result<Self> {
- Ok(Self::from_packet_parser(PacketParser::from_bytes(data)?))
- }
-}
-
-impl std::str::FromStr for TPK {
- type Err = failure::Error;
-
- fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
- Self::from_bytes(s.as_bytes())
- }
-}
-
-impl<'a, I: Iterator<Item=Packet>> TPKParser<'a, I> {
- /// Initializes a TPKParser from an iterator over Packets.
- pub fn from_iter(iter: I) -> Self {
- let mut parser : Self = Default::default();
- parser.source = PacketSource::Iter(iter);
- parser
- }
-
- /// Filters the TPKs prior to validation.
- ///
- /// By default, the `TPKParser` only returns valdiated `TPK`s.
- /// Checking that a `TPK`'s self-signatures are valid, however, is
- /// computationally expensive, and not always necessary. For
- /// example, when looking for a small number of `TPK`s in a large
- /// keyring, most `TPK`s can be immediately discarded. That is,
- /// it is more efficient to filter, validate, and double check,
- /// than to validate and filter. (It is necessary to double
- /// check, because the check might have been on an invalid part.
- /// For example, if searching for a key with a particular key ID,
- /// a matching subkey might not have any self signatures.)
- ///
- /// If the `TPKParser` gave out unvalidated `TPK`s, and provided
- /// an interface to validate them, then the caller could implement
- /// this first-validate-double-check pattern. Giving out
- /// unvalidated `TPK`s, however, is too dangerous: inevitably, a
- /// `TPK` will be used without having been validated in a context
- /// where it should have been.
- ///
- /// This function avoids this class of bugs while still providing
- /// a mechanism to filter `TPK`s prior to validation: the caller
- /// provides a callback, that is invoked on the *unvalidated*
- /// `TPK`. If the callback returns `true`, then the parser
- /// validates the `TPK`, and invokes the callback *a second time*
- /// to make sure the `TPK` is really wanted. If the callback
- /// returns false, then the `TPK` is skipped.
- ///
- /// Note: calling this function multiple times on a single
- /// `TPKParser` will install multiple filters.
- ///
- /// # Example
- ///
- /// ```rust
- /// # extern crate sequoia_openpgp as openpgp;
- /// # use openpgp::Result;
- /// # use openpgp::parse::{Parse, PacketParser};
- /// use openpgp::tpk::TPKParser;
- /// use openpgp::TPK;
- /// use openpgp::KeyID;
- ///
- /// # fn main() { f().unwrap(); }
- /// # fn f() -> Result<()> {
- /// # let ppr = PacketParser::from_bytes(b"")?;
- /// # let some_keyid = KeyID::from_hex("C2B819056C652598").unwrap();
- /// for tpkr in TPKParser::from_packet_parser(ppr)
- /// .unvalidated_tpk_filter(|tpk, _| {
- /// if tpk.primary().key().keyid() == some_keyid {
- /// return true;
- /// }
- /// for binding in tpk.subkeys() {
- /// if binding.key().keyid() == some_keyid {
- /// return true;
- /// }
- /// }
- /// false
- /// })
- /// {
- /// match tpkr {
- /// Ok(tpk) => {
- /// // The TPK contains the subkey.
- /// }
- /// Err(err) => {
- /// eprintln!("Error reading keyring: {}", err);
- /// }
- /// }
- /// }
- /// # Ok(())
- /// # }
- /// ```
- pub fn unvalidated_tpk_filter<F: 'a>(mut self, filter: F) -> Self
- where F: Fn(&TPK, bool) -> bool
- {
- self.filter.push(Box::new(filter));
- self
- }
-
- // Parses the next packet in the packet stream.
- //
- // If we complete parsing a TPK, returns the TPK. Otherwise,
- // returns None.
- fn parse(&mut self, p: Packet) -> Result<Option<TPK>> {
- if self.packets.len() > 0 {
- match p.tag() {
- Tag::PublicKey | Tag::SecretKey => {
- return self.tpk(Some(p));
- },
- _ => {},
- }
- }
-
- self.packets.push(p);
- Ok(None)
- }
-
- // Resets the parser so that it starts parsing a new packet.
- //
- // Returns the old state. Note: the packet iterator is preserved.
- fn reset(&mut self) -> Self {
- // We need to preserve `source`.
- let mut orig = mem::replace(self, Default::default());
- self.source = mem::replace(&mut orig.source, PacketSource::EOF);
- orig
- }
-
- // Finalizes the current TPK and returns it. Sets the parser up to
- // begin parsing the next TPK.
- fn tpk(&mut self, pk: Option<Packet>) -> Result<Option<TPK>> {
- let orig = self.reset();
-
- if let Some(pk) = pk {
- self.packets.push(pk);
- }
-
- let packets = orig.packets.len();
- let tokens = orig.packets
- .into_iter()
- .filter_map(|p| p.into())
- .collect::<Vec<Token>>();
- if tokens.len() != packets {
- // There was at least one packet that doesn't belong in a
- // TPK. Fail now.
- return Err(Error::UnsupportedTPK(
- "Packet sequence includes non-TPK packets.".into()).into());
- }
-
- let tpko = match TPKLowLevelParser::new()
- .parse(Lexer::from_tokens(&tokens))
- {
- Ok(tpko) => tpko,
- Err(e) => return Err(
- parser::low_level::parse_error_to_openpgp_error(
- parser::low_level::parse_error_downcast(e)).into()),
- }.and_then(|tpk| {
- for filter in &self.filter {
- if !filter(&tpk, true) {
- return None;
- }
- }
-
- Some(tpk)
- }).and_then(|mut tpk| {
- fn split_sigs<C>(primary: &Fingerprint, primary_keyid: &KeyID,
- b: &mut ComponentBinding<C>)
- {
- let mut selfsigs = vec![];
- let mut certifications = vec![];
- let mut self_revs = vec![];
- let mut other_revs = vec![];
-
- for sig in mem::replace(&mut b.certifications, vec![]) {
- match sig {
- Signature::V4(sig) => {
- let typ = sig.typ();
-
- let is_selfsig =
- sig.issuer_fingerprint()
- .map(|fp| fp == *primary)
- .unwrap_or(false)
- || sig.issuer()
- .map(|keyid| keyid == *primary_keyid)
- .unwrap_or(false);
-
- use self::SignatureType::*;
- if typ == KeyRevocation
- || typ == SubkeyRevocation
- || typ == CertificateRevocation
- {
- if is_selfsig {
- self_revs.push(sig.into());
- } else {
- other_revs.push(sig.into());
- }
- } else {
- if is_selfsig {
- selfsigs.push(sig.into());
- } else {
- certifications.push(sig.into());
- }
- }
- },
- }
- }
-
- b.selfsigs = selfsigs;
- b.certifications = certifications;
- b.self_revocations = self_revs;
- b.other_revocations = other_revs;
- }
-
- let primary_fp = tpk.primary().key().fingerprint();
- let primary_keyid = primary_fp.to_keyid();
-
- // The parser puts all of the signatures on the
- // certifications field. Split them now.
-
- split_sigs(&primary_fp, &primary_keyid, &mut tpk.primary);
-
- for b in tpk.userids.iter_mut() {
- split_sigs(&primary_fp, &primary_keyid, b);
- }
- for b in tpk.user_attributes.iter_mut() {
- split_sigs(&primary_fp, &primary_keyid, b);
- }
- for b in tpk.subkeys.iter_mut() {
- split_sigs(&primary_fp, &primary_keyid, b);
- }
-
- let tpk = tpk.canonicalize();
-
- // Make sure it is still wanted.
- for filter in &self.filter {
- if !filter(&tpk, true) {
- return None;
- }
- }
-
- Some(tpk)
- });
-
- Ok(tpko)
- }
-}
-
-impl<'a, I: Iterator<Item=Packet>> Iterator for TPKParser<'a, I> {
- type Item = Result<TPK>;
-
- fn next(&mut self) -> Option<Self::Item> {
- loop {
- match mem::replace(&mut self.source, PacketSource::EOF) {
- PacketSource::EOF => {
- if TRACE {
- eprintln!("TPKParser::next: EOF.");
- }
-
- if self.packets.len() == 0 {
- return None;
- }
- match self.tpk(None) {
- Ok(Some(tpk)) => return Some(Ok(tpk)),
- Ok(None) => return None,
- Err(err) => return Some(Err(err)),
- }
- },
- PacketSource::PacketParser(pp) => {
- match pp.next() {
- Ok((packet, ppr)) => {
- if let PacketParserResult::Some(pp) = ppr {
- self.source = PacketSource::PacketParser(pp);
- }
-
- match self.parse(packet) {
- Ok(Some(tpk)) => return Some(Ok(tpk)),
- Ok(None) => (),
- Err(err) => return Some(Err(err)),
- }
- },
- Err(err) => {
- self.saw_error = true;
- return Some(Err(err));
- }
- }
- },
- PacketSource::Iter(mut iter) => {
- let r = match iter.next() {
- Some(packet) => {
- self.source = PacketSource::Iter(iter);
- self.parse(packet)
- }
- None if self.packets.len() == 0 => Ok(None),
- None => self.tpk(None),
- };
-
- match r {
- Ok(Some(tpk)) => {
- if TRACE {
- eprintln!("TPKParser::next => {}",
- tpk.primary().key().fingerprint());
- }
- return Some(Ok(tpk));
- }
- Ok(None) => (),
- Err(err) => return Some(Err(err)),
- }
- },
- }
- }
- }
-}
-
impl fmt::Display for TPK {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.primary().key().fingerprint())
@@ -832,6 +424,14 @@ pub struct TPK {
bad: Vec<packet::Signature>,
}
+impl std::str::FromStr for TPK {
+ type Err = failure::Error;
+
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+ Self::from_bytes(s.as_bytes())
+ }
+}
+
impl<'a> Parse<'a, TPK> for TPK {
/// Returns the first TPK encountered in the reader.
fn from_reader<R: io::Read>(reader: R) -> Result<Self> {
@@ -1208,7 +808,7 @@ impl TPK {
/// packet stream is a keyring, this function will return
/// `Error::MalformedTPK`.
pub fn from_packet_parser(ppr: PacketParserResult) -> Result<Self> {
- let mut parser = TPKParser::from_packet_parser(ppr);
+ let mut parser = parser::TPKParser::from_packet_parser(ppr);
if let Some(tpk_result) = parser.next() {
if parser.next().is_some() {
Err(Error::MalformedTPK(
@@ -1224,7 +824,7 @@ impl TPK {
/// Returns the first TPK found in the `PacketPile`.
pub fn from_packet_pile(p: PacketPile) -> Result<Self> {
- let mut i = TPKParser::from_iter(p.into_children());
+ let mut i = parser::TPKParser::from_iter(p.into_children());
match i.next() {
Some(Ok(tpk)) => Ok(tpk),
Some(Err(err)) => Err(err),
@@ -2402,6 +2002,7 @@ mod test {
#[test]
fn merge_packets() {
use crate::armor;
+ use crate::packet::Tag;
// Merge the revocation certificate into the TPK and make sure
// it shows up.
diff --git a/openpgp/src/tpk/parser/mod.rs b/openpgp/src/tpk/parser/mod.rs
index 21015aca..a4d118b8 100644
--- a/openpgp/src/tpk/parser/mod.rs
+++ b/openpgp/src/tpk/parser/mod.rs
@@ -1,13 +1,28 @@
+use std::io;
+use std::mem;
use std::vec;
+use std::path::Path;
use lalrpop_util::ParseError;
use crate::{
Error,
+ Fingerprint,
+ KeyID,
packet::Tag,
+ packet::Signature,
+ Packet,
+ parse::{
+ Parse,
+ PacketParserResult,
+ PacketParser
+ },
+ Result,
+ tpk::ComponentBinding,
+ TPK,
};
-pub mod low_level;
+mod low_level;
use low_level::{
Lexer,
TPKParser as TPKLowLevelParser,
@@ -16,6 +31,8 @@ use low_level::{
parse_error_downcast,
};
+use super::TRACE;
+
/// Whether a packet sequence is a valid key ring.
#[derive(Debug)]
pub enum KeyringValidity {
@@ -355,6 +372,399 @@ impl TPKValidator {
}
}
+// A TPKParser can read packets from either an Iterator or a
+// PacketParser. Ideally, we would just take an iterator, but we
+// want to be able to handle errors, which iterators hide.
+enum PacketSource<'a, I: Iterator<Item=Packet>> {
+ EOF,
+ PacketParser(PacketParser<'a>),
+ Iter(I),
+}
+
+/// An iterator over a sequence of TPKs (e.g., an OpenPGP keyring).
+///
+/// The source of packets can either be a `PacketParser` or an
+/// iterator over `Packet`s. (In the latter case, the underlying
+/// parser is not able to propagate errors. Thus, this is only
+/// appropriate for in-memory structures, like a vector of `Packet`s
+/// or a `PacketPile`.)
+///
+/// # Example
+///
+/// ```rust
+/// # extern crate sequoia_openpgp as openpgp;
+/// # use openpgp::Result;
+/// # use openpgp::parse::{Parse, PacketParserResult, PacketParser};
+/// use openpgp::tpk::TPKParser;
+///
+/// # fn main() { f().unwrap(); }
+/// # fn f() -> Result<()> {
+/// # let ppr = PacketParser::from_bytes(b"")?;
+/// for tpko in TPKParser::from_packet_parser(ppr) {
+/// match tpko {
+/// Ok(tpk) => {
+/// println!("Key: {}", tpk.primary().key());
+/// for binding in tpk.userids() {
+/// println!("User ID: {}", binding.userid());
+/// }
+/// }
+/// Err(err) => {
+/// eprintln!("Error reading keyring: {}", err);
+/// }
+/// }
+/// }
+/// # Ok(())
+/// # }
+/// ```
+pub struct TPKParser<'a, I: Iterator<Item=Packet>> {
+ source: PacketSource<'a, I>,
+ packets: Vec<Packet>,
+ saw_error: bool,
+ filter: Vec<Box<Fn(&TPK, bool) -> bool + 'a>>,
+}
+
+impl<'a, I: Iterator<Item=Packet>> Default for TPKParser<'a, I> {
+ fn default() -> Self {
+ TPKParser {
+ source: PacketSource::EOF,
+ packets: vec![],
+ saw_error: false,
+ filter: vec![],
+ }
+ }
+}
+
+// When using a `PacketParser`, we never use the `Iter` variant.
+// Nevertheless, we need to provide a concrete type.
+// vec::IntoIter<Packet> is about as good as any other.
+impl<'a> TPKParser<'a, vec::IntoIter<Packet>> {
+ /// Initializes a `TPKParser` from a `PacketParser`.
+ pub fn from_packet_parser(ppr: PacketParserResult<'a>) -> Self {
+ let mut parser : Self = Default::default();
+ if let PacketParserResult::Some(pp) = ppr {
+ parser.source = PacketSource::PacketParser(pp);
+ }
+ parser
+ }
+}
+
+impl<'a> Parse<'a, TPKParser<'a, vec::IntoIter<Packet>>>
+ for TPKParser<'a, vec::IntoIter<Packet>>
+{
+ /// Initializes a `TPKParser` from a `Read`er.
+ fn from_reader<R: 'a + io::Read>(reader: R) -> Result<Self> {
+ Ok(Self::from_packet_parser(PacketParser::from_reader(reader)?))
+ }
+
+ /// Initializes a `TPKParser` from a `File`.
+ fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
+ Ok(Self::from_packet_parser(PacketParser::from_file(path)?))
+ }
+
+ /// Initializes a `TPKParser` from a byte string.
+ fn from_bytes(data: &'a [u8]) -> Result<Self> {
+ Ok(Self::from_packet_parser(PacketParser::from_bytes(data)?))
+ }
+}
+
+impl<'a, I: Iterator<Item=Packet>> TPKParser<'a, I> {
+ /// Initializes a TPKParser from an iterator over Packets.
+ pub fn from_iter(iter: I) -> Self {
+ let mut parser : Self = Default::default();
+ parser.source = PacketSource::Iter(iter);
+ parser
+ }
+
+ /// Filters the TPKs prior to validation.
+ ///
+ /// By default, the `TPKParser` only returns valdiated `TPK`s.
+ /// Checking that a `TPK`'s self-signatures are valid, however, is
+ /// computationally expensive, and not always necessary. For
+ /// example, when looking for a small number of `TPK`s in a large
+ /// keyring, most `TPK`s can be immediately discarded. That is,
+ /// it is more efficient to filter, validate, and double check,
+ /// than to validate and filter. (It is necessary to double
+ /// check, because the check might have been on an invalid part.
+ /// For example, if searching for a key with a particular key ID,
+ /// a matching subkey might not have any self signatures.)
+ ///
+ /// If the `TPKParser` gave out unvalidated `TPK`s, and provided
+ /// an interface to validate them, then the caller could implement
+ /// this first-validate-double-check pattern. Giving out
+ /// unvalidated `TPK`s, however, is too dangerous: inevitably, a
+ /// `TPK` will be used without having been validated in a context
+ /// where it should have been.
+ ///
+ /// This function avoids this class of bugs while still providing
+ /// a mechanism to filter `TPK`s prior to validation: the caller
+ /// provides a callback, that is invoked on the *unvalidated*
+ /// `TPK`. If the callback returns `true`, then the parser
+ /// validates the `TPK`, and invokes the callback *a second time*
+ /// to make sure the `TPK` is really wanted. If the callback
+ /// returns false, then the `TPK` is skipped.
+ ///
+ /// Note: calling this function multiple times on a single
+ /// `TPKParser` will install multiple filters.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// # use openpgp::Result;
+ /// # use openpgp::parse::{Parse, PacketParser};
+ /// use openpgp::tpk::TPKParser;
+ /// use openpgp::TPK;
+ /// use openpgp::KeyID;
+ ///
+ /// # fn main() { f().unwrap(); }
+ /// # fn f() -> Result<()> {
+ /// # let ppr = PacketParser::from_bytes(b"")?;
+ /// # let some_keyid = KeyID::from_hex("C2B819056C652598").unwrap();
+ /// for tpkr in TPKParser::from_packet_parser(ppr)
+ /// .unvalidated_tpk_filter(|tpk, _| {
+ /// if tpk.primary().key().keyid() == some_keyid {
+ /// return true;
+ /// }
+ /// for binding in tpk.subkeys() {
+ /// if binding.key().keyid() == some_keyid {
+ /// return true;
+ /// }
+ /// }
+ /// false
+ /// })
+ /// {
+ /// match tpkr {
+ /// Ok(tpk) => {
+ /// // The TPK contains the subkey.
+ /// }
+ /// Err(err) => {
+ /// eprintln!("Error reading keyring: {}", err);
+ /// }
+ /// }
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn unvalidated_tpk_filter<F: 'a>(mut self, filter: F) -> Self
+ where F: Fn(&TPK, bool) -> bool
+ {
+ self.filter.push(Box::new(filter));
+ self
+ }
+
+ // Parses the next packet in the packet stream.
+ //
+ // If we complete parsing a TPK, returns the TPK. Otherwise,
+ // returns None.
+ fn parse(&mut self, p: Packet) -> Result<Option<TPK>> {
+ if self.packets.len() > 0 {
+ match p.tag() {
+ Tag::PublicKey | Tag::SecretKey => {
+ return self.tpk(Some(p));
+ },
+ _ => {},
+ }
+ }
+
+ self.packets.push(p);
+ Ok(None)
+ }
+
+ // Resets the parser so that it starts parsing a new packet.
+ //
+ // Returns the old state. Note: the packet iterator is preserved.
+ fn reset(&mut self) -> Self {
+ // We need to preserve `source`.
+ let mut orig = mem::replace(self, Default::default());
+ self.source = mem::replace(&mut orig.source, PacketSource::EOF);
+ orig
+ }
+
+ // Finalizes the current TPK and returns it. Sets the parser up to
+ // begin parsing the next TPK.
+ fn tpk(&mut self, pk: Option<Packet>) -> Result<Option<TPK>> {
+ let orig = self.reset();
+
+ if let Some(pk) = pk {
+ self.packets.push(pk);
+ }
+
+ let packets = orig.packets.len();
+ let tokens = orig.packets
+ .into_iter()
+ .filter_map(|p| p.into())
+ .collect::<Vec<Token>>();
+ if tokens.len() != packets {
+ // There was at least one packet that doesn't belong in a
+ // TPK. Fail now.
+ return Err(Error::UnsupportedTPK(
+ "Packet sequence includes non-TPK packets.".into()).into());
+ }
+
+ let tpko = match TPKLowLevelParser::new()
+ .parse(Lexer::from_tokens(&tokens))
+ {
+ Ok(tpko) => tpko,
+ Err(e) => return Err(
+ low_level::parse_error_to_openpgp_error(
+ low_level::parse_error_downcast(e)).into()),
+ }.and_then(|tpk| {
+ for filter in &self.filter {
+ if !filter(&tpk, true) {
+ return None;
+ }
+ }
+
+ Some(tpk)
+ }).and_then(|mut tpk| {
+ fn split_sigs<C>(primary: &Fingerprint, primary_keyid: &KeyID,
+ b: &mut ComponentBinding<C>)
+ {
+ let mut selfsigs = vec![];
+ let mut certifications = vec![];
+ let mut self_revs = vec![];
+ let mut other_revs = vec![];
+
+ for sig in mem::replace(&mut b.certifications, vec![]) {
+ match sig {
+ Signature::V4(sig) => {
+ let typ = sig.typ();
+
+ let is_selfsig =