summaryrefslogtreecommitdiffstats
path: root/openpgp/src/cert/parser/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src/cert/parser/mod.rs')
-rw-r--r--openpgp/src/cert/parser/mod.rs931
1 files changed, 931 insertions, 0 deletions
diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs
new file mode 100644
index 00000000..74854021
--- /dev/null
+++ b/openpgp/src/cert/parser/mod.rs
@@ -0,0 +1,931 @@
+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,
+ cert::ComponentBinding,
+ Cert,
+};
+
+mod low_level;
+use low_level::{
+ Lexer,
+ CertParser as CertLowLevelParser,
+ CertParserError,
+ Token,
+ parse_error_downcast,
+};
+
+use super::TRACE;
+
+/// Whether a packet sequence is a valid key ring.
+#[derive(Debug)]
+pub enum KeyringValidity {
+ /// The packet sequence is a valid key ring.
+ Keyring,
+ /// The packet sequence is a valid key ring prefix.
+ KeyringPrefix,
+ /// The packet sequence is definitely not a key ring.
+ Error(failure::Error),
+}
+
+impl KeyringValidity {
+ /// Returns whether the packet sequence is a valid key ring.
+ ///
+ /// Note: a `KeyringValidator` will only return this after
+ /// `KeyringValidator::finish` has been called.
+ pub fn is_keyring(&self) -> bool {
+ if let KeyringValidity::Keyring = self {
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Returns whether the packet sequence is a valid Keyring prefix.
+ ///
+ /// Note: a `KeyringValidator` will only return this before
+ /// `KeyringValidator::finish` has been called.
+ pub fn is_keyring_prefix(&self) -> bool {
+ if let KeyringValidity::KeyringPrefix = self {
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Returns whether the packet sequence is definitely not a valid
+ /// key ring.
+ pub fn is_err(&self) -> bool {
+ if let KeyringValidity::Error(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+}
+
+/// Used to help validate that a packet sequence is a valid key ring.
+#[derive(Debug)]
+pub struct KeyringValidator {
+ tokens: Vec<Token>,
+ n_keys: usize,
+ n_packets: usize,
+ finished: bool,
+
+ // If we know that the packet sequence is invalid.
+ error: Option<CertParserError>,
+}
+
+impl Default for KeyringValidator {
+ fn default() -> Self {
+ KeyringValidator::new()
+ }
+}
+
+impl KeyringValidator {
+ /// Instantiates a new `KeyringValidator`.
+ pub fn new() -> Self {
+ KeyringValidator {
+ tokens: vec![],
+ n_keys: 0,
+ n_packets: 0,
+ finished: false,
+ error: None,
+ }
+ }
+
+ /// Returns whether the packet sequence is a valid keyring.
+ ///
+ /// Note: a `KeyringValidator` will only return this after
+ /// `KeyringValidator::finish` has been called.
+ pub fn is_keyring(&self) -> bool {
+ self.check().is_keyring()
+ }
+
+ /// Returns whether the packet sequence forms a valid keyring
+ /// prefix.
+ ///
+ /// Note: a `KeyringValidator` will only return this before
+ /// `KeyringValidator::finish` has been called.
+ pub fn is_keyring_prefix(&self) -> bool {
+ self.check().is_keyring_prefix()
+ }
+
+ /// Returns whether the packet sequence is definitely not a valid
+ /// keyring.
+ pub fn is_err(&self) -> bool {
+ self.check().is_err()
+ }
+
+ /// Add the token `token` to the token stream.
+ pub fn push_token(&mut self, token: Token) {
+ assert!(!self.finished);
+
+ if self.error.is_some() {
+ return;
+ }
+
+ match token {
+ Token::PublicKey(_) | Token::SecretKey(_) => {
+ self.tokens.clear();
+ self.n_keys += 1;
+ },
+ _ => (),
+ }
+
+ self.n_packets += 1;
+ if destructures_to!(Token::Signature(None) = &token)
+ && destructures_to!(Some(Token::Signature(None)) = self.tokens.last())
+ {
+ // Compress multiple signatures in a row. This is
+ // essential for dealing with flooded keys.
+ } else {
+ self.tokens.push(token);
+ }
+ }
+
+ /// Add a packet of type `tag` to the token stream.
+ pub fn push(&mut self, tag: Tag) {
+ let token = match tag {
+ Tag::PublicKey => Token::PublicKey(None),
+ Tag::SecretKey => Token::SecretKey(None),
+ Tag::PublicSubkey => Token::PublicSubkey(None),
+ Tag::SecretSubkey => Token::SecretSubkey(None),
+ Tag::UserID => Token::UserID(None),
+ Tag::UserAttribute => Token::UserAttribute(None),
+ Tag::Signature => Token::Signature(None),
+ Tag::Trust => Token::Trust(None),
+ _ => {
+ // Unknown token.
+ self.error = Some(CertParserError::OpenPGP(
+ Error::MalformedMessage(
+ format!("Invalid Cert: {:?} packet (at {}) not expected",
+ tag, self.n_packets).into())));
+ self.tokens.clear();
+ return;
+ }
+ };
+
+ self.push_token(token)
+ }
+
+ /// Note that the entire message has been seen.
+ ///
+ /// This function may only be called once.
+ ///
+ /// Once called, this function will no longer return
+ /// `KeyringValidity::KeyringPrefix`.
+ pub fn finish(&mut self) {
+ assert!(!self.finished);
+ self.finished = true;
+ }
+
+ /// Returns whether the token stream corresponds to a valid
+ /// keyring.
+ ///
+ /// This returns a tri-state: if the packet sequence is a valid
+ /// Keyring, it returns KeyringValidity::Keyring, if the packet sequence is
+ /// invalid, then it returns KeyringValidity::Error. If the packet
+ /// sequence could be valid, then it returns
+ /// KeyringValidity::KeyringPrefix.
+ ///
+ /// Note: if KeyringValidator::finish() *hasn't* been called, then
+ /// this function will only ever return either
+ /// KeyringValidity::KeyringPrefix or KeyringValidity::Error. Once
+ /// KeyringValidity::finish() has been called, then only
+ /// KeyringValidity::Keyring or KeyringValidity::Bad will be called.
+ pub fn check(&self) -> KeyringValidity {
+ if let Some(ref err) = self.error {
+ return KeyringValidity::Error((*err).clone().into());
+ }
+
+ let r = CertLowLevelParser::new().parse(
+ Lexer::from_tokens(&self.tokens));
+
+ if self.finished {
+ match r {
+ Ok(_) => KeyringValidity::Keyring,
+ Err(err) =>
+ KeyringValidity::Error(
+ CertParserError::Parser(parse_error_downcast(err)).into()),
+ }
+ } else {
+ match r {
+ Ok(_) => KeyringValidity::KeyringPrefix,
+ Err(ParseError::UnrecognizedEOF { .. }) =>
+ KeyringValidity::KeyringPrefix,
+ Err(err) =>
+ KeyringValidity::Error(
+ CertParserError::Parser(parse_error_downcast(err)).into()),
+ }
+ }
+ }
+}
+
+/// Whether a packet sequence is a valid Cert.
+#[derive(Debug)]
+pub enum CertValidity {
+ /// The packet sequence is a valid Cert.
+ Cert,
+ /// The packet sequence is a valid Cert prefix.
+ CertPrefix,
+ /// The packet sequence is definitely not a Cert.
+ Error(failure::Error),
+}
+
+impl CertValidity {
+ /// Returns whether the packet sequence is a valid Cert.
+ ///
+ /// Note: a `CertValidator` will only return this after
+ /// `CertValidator::finish` has been called.
+ pub fn is_cert(&self) -> bool {
+ if let CertValidity::Cert = self {
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Returns whether the packet sequence is a valid Cert prefix.
+ ///
+ /// Note: a `CertValidator` will only return this before
+ /// `CertValidator::finish` has been called.
+ pub fn is_cert_prefix(&self) -> bool {
+ if let CertValidity::CertPrefix = self {
+ true
+ } else {
+ false
+ }
+ }
+
+ /// Returns whether the packet sequence is definitely not a valid
+ /// Cert.
+ pub fn is_err(&self) -> bool {
+ if let CertValidity::Error(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+}
+
+/// Used to help validate that a packet sequence is a valid Cert.
+#[derive(Debug)]
+pub struct CertValidator(KeyringValidator);
+
+impl Default for CertValidator {
+ fn default() -> Self {
+ CertValidator::new()
+ }
+}
+
+impl CertValidator {
+ /// Instantiates a new `CertValidator`.
+ pub fn new() -> Self {
+ CertValidator(Default::default())
+ }
+
+ /// Returns whether the packet sequence is a valid Cert.
+ ///
+ /// Note: a `CertValidator` will only return this after
+ /// `CertValidator::finish` has been called.
+ pub fn is_cert(&self) -> bool {
+ self.check().is_cert()
+ }
+
+ /// Returns whether the packet sequence forms a valid Cert
+ /// prefix.
+ ///
+ /// Note: a `CertValidator` will only return this before
+ /// `CertValidator::finish` has been called.
+ pub fn is_cert_prefix(&self) -> bool {
+ self.check().is_cert_prefix()
+ }
+
+ /// Returns whether the packet sequence is definitely not a valid
+ /// Cert.
+ pub fn is_err(&self) -> bool {
+ self.check().is_err()
+ }
+
+ /// Add the token `token` to the token stream.
+ pub fn push_token(&mut self, token: Token) {
+ self.0.push_token(token)
+ }
+
+ /// Add a packet of type `tag` to the token stream.
+ pub fn push(&mut self, tag: Tag) {
+ self.0.push(tag)
+ }
+
+ /// Note that the entire message has been seen.
+ ///
+ /// This function may only be called once.
+ ///
+ /// Once called, this function will no longer return
+ /// `CertValidity::CertPrefix`.
+ pub fn finish(&mut self) {
+ self.0.finish()
+ }
+
+ /// Returns whether the token stream corresponds to a valid
+ /// Cert.
+ ///
+ /// This returns a tri-state: if the packet sequence is a valid
+ /// Cert, it returns CertValidity::Cert, if the packet sequence is
+ /// invalid, then it returns CertValidity::Error. If the packet
+ /// sequence could be valid, then it returns
+ /// CertValidity::CertPrefix.
+ ///
+ /// Note: if CertValidator::finish() *hasn't* been called, then
+ /// this function will only ever return either
+ /// CertValidity::CertPrefix or CertValidity::Error. Once
+ /// CertValidity::finish() has been called, then only
+ /// CertValidity::Cert or CertValidity::Bad will be called.
+ pub fn check(&self) -> CertValidity {
+ if self.0.n_keys > 1 {
+ return CertValidity::Error(Error::MalformedMessage(
+ "More than one key found, this is a keyring".into()).into());
+ }
+
+ match self.0.check() {
+ KeyringValidity::Keyring => CertValidity::Cert,
+ KeyringValidity::KeyringPrefix => CertValidity::CertPrefix,
+ KeyringValidity::Error(e) => CertValidity::Error(e),
+ }
+ }
+}
+
+// A CertParser 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 Certs (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::cert::CertParser;
+///
+/// # fn main() { f().unwrap(); }
+/// # fn f() -> Result<()> {
+/// # let ppr = PacketParser::from_bytes(b"")?;
+/// for certo in CertParser::from_packet_parser(ppr) {
+/// match certo {
+/// Ok(cert) => {
+/// println!("Key: {}", cert.primary());
+/// for binding in cert.userids() {
+/// println!("User ID: {}", binding.userid());
+/// }
+/// }
+/// Err(err) => {
+/// eprintln!("Error reading keyring: {}", err);
+/// }
+/// }
+/// }
+/// # Ok(())
+/// # }
+/// ```
+pub struct CertParser<'a, I: Iterator<Item=Packet>> {
+ source: PacketSource<'a, I>,
+ packets: Vec<Packet>,
+ saw_error: bool,
+ filter: Vec<Box<dyn Fn(&Cert, bool) -> bool + 'a>>,
+}
+
+impl<'a, I: Iterator<Item=Packet>> Default for CertParser<'a, I> {
+ fn default() -> Self {
+ CertParser {
+ 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> CertParser<'a, vec::IntoIter<Packet>> {
+ /// Initializes a `CertParser` 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, CertParser<'a, vec::IntoIter<Packet>>>
+ for CertParser<'a, vec::IntoIter<Packet>>
+{
+ /// Initializes a `CertParser` 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 `CertParser` from a `File`.
+ fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
+ Ok(Self::from_packet_parser(PacketParser::from_file(path)?))
+ }
+
+ /// Initializes a `CertParser` from a byte string.
+ fn from_bytes<D: AsRef<[u8]> + ?Sized>(data: &'a D) -> Result<Self> {
+ Ok(Self::from_packet_parser(PacketParser::from_bytes(data)?))
+ }
+}
+
+impl<'a, I: Iterator<Item=Packet>> CertParser<'a, I> {
+ /// Initializes a CertParser 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 Certs prior to validation.
+ ///
+ /// By default, the `CertParser` only returns valdiated `Cert`s.
+ /// Checking that a `Cert`'s self-signatures are valid, however, is
+ /// computationally expensive, and not always necessary. For
+ /// example, when looking for a small number of `Cert`s in a large
+ /// keyring, most `Cert`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 `CertParser` gave out unvalidated `Cert`s, and provided
+ /// an interface to validate them, then the caller could implement
+ /// this first-validate-double-check pattern. Giving out
+ /// unvalidated `Cert`s, however, is too dangerous: inevitably, a
+ /// `Cert` 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 `Cert`s prior to validation: the caller
+ /// provides a callback, that is invoked on the *unvalidated*
+ /// `Cert`. If the callback returns `true`, then the parser
+ /// validates the `Cert`, and invokes the callback *a second time*
+ /// to make sure the `Cert` is really wanted. If the callback
+ /// returns false, then the `Cert` is skipped.
+ ///
+ /// Note: calling this function multiple times on a single
+ /// `CertParser` will install multiple filters.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// # extern crate sequoia_openpgp as openpgp;
+ /// # use openpgp::Result;
+ /// # use openpgp::parse::{Parse, PacketParser};
+ /// use openpgp::cert::CertParser;
+ /// use openpgp::Cert;
+ /// 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 certr in CertParser::from_packet_parser(ppr)
+ /// .unvalidated_cert_filter(|cert, _| {
+ /// if cert.primary().keyid() == some_keyid {
+ /// return true;
+ /// }
+ /// for binding in cert.subkeys() {
+ /// if binding.key().keyid() == some_keyid {
+ /// return true;
+ /// }
+ /// }
+ /// false
+ /// })
+ /// {
+ /// match certr {
+ /// Ok(cert) => {
+ /// // The Cert contains the subkey.
+ /// }
+ /// Err(err) => {
+ /// eprintln!("Error reading keyring: {}", err);
+ /// }
+ /// }
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ pub fn unvalidated_cert_filter<F: 'a>(mut self, filter: F) -> Self
+ where F: Fn(&Cert, bool) -> bool
+ {
+ self.filter.push(Box::new(filter));
+ self
+ }
+
+ // Parses the next packet in the packet stream.
+ //
+ // If we complete parsing a Cert, returns the Cert. Otherwise,
+ // returns None.
+ fn parse(&mut self, p: Packet) -> Result<Option<Cert>> {
+ if let Packet::Marker(_) = p {
+ // Ignore Marker Packet. RFC4880, section 5.8:
+ //
+ // Such a packet MUST be ignored when received.
+ return Ok(None);
+ }
+
+ if self.packets.len() > 0 {
+ match p.tag() {
+ Tag::PublicKey | Tag::SecretKey => {
+ return self.cert(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 Cert and returns it. Sets the parser up to
+ // begin parsing the next Cert.
+ fn cert(&mut self, pk: Option<Packet>) -> Result<Option<Cert>> {
+ 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
+ // Cert. Fail now.
+ return Err(Error::UnsupportedCert(
+ "Packet sequence includes non-Cert packets.".into()).into());
+ }
+
+ let certo = match CertLowLevelParser::new()
+ .parse(Lexer::from_tokens(&tokens))
+ {
+ Ok(certo) => certo,
+ Err(e) => return Err(
+ low_level::parse_error_to_openpgp_error(
+ low_level::parse_error_downcast(e)).into()),
+ }.and_then(|cert| {
+ for filter in &self.filter {
+ if !filter(&cert, true) {
+ return None;
+ }
+ }
+
+ Some(cert)
+ }).and_then(|mut cert| {
+ fn split_sigs<C>(primary: &Fingerprint, primary_keyid: &KeyID,
+ b: &mut ComponentBinding<C>)
+ {
+ let mut self_signatures = 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 crate::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 {
+ self_signatures.push(sig.into());
+ } else {
+ certifications.push(sig.into());
+ }
+ }
+ },
+ }
+ }
+
+ b.self_signatures = self_signatures;
+ b.certifications = certifications;
+ b.self_revocations = self_revs;
+ b.other_revocations = other_revs;
+ }
+
+ let primary_fp = cert.primary().fingerprint();
+ let primary_keyid = KeyID::from(&primary_fp);
+
+ // The parser puts all of the signatures on the
+ // certifications field. Split them now.
+
+ split_sigs(&primary_fp, &primary_keyid, &mut cert.primary);
+
+ for b in cert.userids.iter_mut() {
+ split_sigs(&primary_fp, &primary_keyid, b);
+ }
+ for b in cert.user_attributes.iter_mut() {
+ split_sigs(&primary_fp, &primary_keyid, b);
+ }
+ for b in cert.subkeys.iter_mut() {
+ split_sigs(&primary_fp, &primary_keyid, b);
+ }
+
+ let cert = cert.canonicalize();
+
+ // Make sure it is still wanted.
+ for filter in &self.filter {
+ if !filter(&cert, true) {
+ return None;
+ }
+ }
+
+ Some(cert)
+ });
+
+ Ok(certo)
+ }
+}
+
+impl<'a, I: Iterator<Item=Packet>> Iterator for CertParser<'a, I> {
+ type Item = Result<Cert>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ match mem::replace(&mut self.source, PacketSource::EOF) {
+ PacketSource::EOF => {
+ if TRACE {
+ eprintln!("CertParser::next: EOF.");
+ }
+
+ if self.packets.len() == 0 {
+ return None;
+ }
+ match self.cert(None) {
+ Ok(Some(cert)) => return Some(Ok(cert)),
+ 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(cert)) => return Some(Ok(cert)),
+ 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.cert(None),
+ };
+
+ match r {
+ Ok(Some(cert)) => {
+ if TRACE {
+ eprintln!("CertParser::next => {}",
+ cert.primary().fingerprint());
+ }
+ return Some(Ok(cert));
+ }
+ Ok(None) => (),
+ Err(err) => return Some(Err(err)),
+ }
+ },
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn tokens() {
+ use crate::cert::parser::low_level::lexer::{Token, Lexer};
+ use crate::cert::parser::low_level::lexer::Token::*;
+ use crate::cert::parser::low_level::CertParser;
+
+ struct TestVector<'a> {
+ s: &'a [Token],
+ result: bool,
+ }
+
+ let test_vectors = [
+ TestVector {
+ s: &[ PublicKey(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ SecretKey(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ PublicKey(None), Signature(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ PublicKey(None), Signature(None), Signature(None) ],
+ result: true,
+ },
+
+ TestVector {
+ s: &[ PublicKey(None), Signature(None), Signature(None),
+ UserID(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ PublicKey(None), Signature(None), Signature(None),
+ UserID(None), Signature(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ PublicKey(None), Signature(None), Signature(None),
+ UserAttribute(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ PublicKey(None), Signature(None), Signature(None),
+ UserAttribute(None), Signature(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ PublicKey(None), Signature(None), Signature(None),
+ PublicSubkey(None) ],
+ result: true,
+ },
+ TestVector {
+ s: &[ PublicKey(None), Signature(None), Signature(None),
+ PublicSubkey(None), Signature(None) ],
+