diff options
-rw-r--r-- | openpgp/NEWS | 3 | ||||
-rw-r--r-- | openpgp/src/cert.rs | 6 | ||||
-rw-r--r-- | openpgp/src/cert/parser/low_level/grammar.lalrpop | 25 | ||||
-rw-r--r-- | openpgp/src/cert/parser/low_level/lexer.rs | 28 | ||||
-rw-r--r-- | openpgp/src/cert/parser/mod.rs | 48 | ||||
-rw-r--r-- | openpgp/src/lib.rs | 5 |
6 files changed, 84 insertions, 31 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS index a69105d7..fd6611d0 100644 --- a/openpgp/NEWS +++ b/openpgp/NEWS @@ -4,7 +4,10 @@ * Changes in 1.10.0 ** New functionality + - Error::UnsupportedCert2 - TryFrom<Packet> for Unknown +** Deprecated functionality + - Error::UnsupportedCert, use Error::UnsupportedCert2 instead * Changes in 1.9.0 ** New functionality - AEADAlgorithm::nonce_size replaces AEADAlgorithm::iv_size diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs index b9550210..005e6a41 100644 --- a/openpgp/src/cert.rs +++ b/openpgp/src/cert.rs @@ -4123,16 +4123,16 @@ mod test { // v3 primary keys are not supported. let cert = Cert::from_bytes(crate::tests::key("john-v3.pgp")); - assert_match!(Error::UnsupportedCert(_) + assert_match!(Error::UnsupportedCert2(..) = cert.err().unwrap().downcast::<Error>().unwrap()); let cert = Cert::from_bytes(crate::tests::key("john-v3-secret.pgp")); - assert_match!(Error::UnsupportedCert(_) + assert_match!(Error::UnsupportedCert2(..) = cert.err().unwrap().downcast::<Error>().unwrap()); // Lutz's key is a v3 key. let cert = Cert::from_bytes(crate::tests::key("lutz.gpg")); - assert_match!(Error::UnsupportedCert(_) + assert_match!(Error::UnsupportedCert2(..) = cert.err().unwrap().downcast::<Error>().unwrap()); // v3 certifications are not supported diff --git a/openpgp/src/cert/parser/low_level/grammar.lalrpop b/openpgp/src/cert/parser/low_level/grammar.lalrpop index 59462c8c..c5146a77 100644 --- a/openpgp/src/cert/parser/low_level/grammar.lalrpop +++ b/openpgp/src/cert/parser/low_level/grammar.lalrpop @@ -83,11 +83,28 @@ pub Cert: Option<Cert> = { Ok(Some(cert)) } - Some((Packet::Unknown(unknown), _sigs)) => { + Some((Packet::Unknown(unknown), sigs)) => { + let mut packets: Vec<Packet> = Default::default(); + packets.push(unknown.into()); + for sig in sigs { + packets.push(sig.into()); + } + for c in c.unwrap_or_default().into_iter() { + match c { + Component::SubkeyBundle(b) => + b.into_packets().for_each(|p| packets.push(p)), + Component::UserIDBundle(b) => + b.into_packets().for_each(|p| packets.push(p)), + Component::UserAttributeBundle(b) => + b.into_packets().for_each(|p| packets.push(p)), + Component::UnknownBundle(b) => + b.into_packets().for_each(|p| packets.push(p)), + } + } Err(ParseError::User { - error: Error::UnsupportedCert(format!( - "Unsupported primary key: Unparsable {} ({:?}).", - unknown.tag(), unknown).into()) + error: Error::UnsupportedCert2( + "Unsupported primary key".into(), + packets), }) } None => { diff --git a/openpgp/src/cert/parser/low_level/lexer.rs b/openpgp/src/cert/parser/low_level/lexer.rs index 0838d2b1..8cd23c5b 100644 --- a/openpgp/src/cert/parser/low_level/lexer.rs +++ b/openpgp/src/cert/parser/low_level/lexer.rs @@ -112,20 +112,22 @@ impl From<Token> for Option<Packet> { } } -impl From<Packet> for Option<Token> { - fn from(p: Packet) -> Self { +impl std::convert::TryFrom<Packet> for Token { + type Error = Packet; + + fn try_from(p: Packet) -> std::result::Result<Self, Self::Error> { match p.tag() { - Tag::PublicKey => Some(Token::PublicKey(Some(p))), - Tag::SecretKey => Some(Token::SecretKey(Some(p))), - Tag::PublicSubkey => Some(Token::PublicSubkey(Some(p))), - Tag::SecretSubkey => Some(Token::SecretSubkey(Some(p))), - Tag::UserID => Some(Token::UserID(Some(p))), - Tag::UserAttribute => Some(Token::UserAttribute(Some(p))), - Tag::Signature => Some(Token::Signature(Some(p))), - Tag::Trust => Some(Token::Trust(Some(p))), - t @ Tag::Unknown(_) => Some(Token::Unknown(t, Some(p))), - t @ Tag::Private(_) => Some(Token::Unknown(t, Some(p))), - _ => None, + Tag::PublicKey => Ok(Token::PublicKey(Some(p))), + Tag::SecretKey => Ok(Token::SecretKey(Some(p))), + Tag::PublicSubkey => Ok(Token::PublicSubkey(Some(p))), + Tag::SecretSubkey => Ok(Token::SecretSubkey(Some(p))), + Tag::UserID => Ok(Token::UserID(Some(p))), + Tag::UserAttribute => Ok(Token::UserAttribute(Some(p))), + Tag::Signature => Ok(Token::Signature(Some(p))), + Tag::Trust => Ok(Token::Trust(Some(p))), + t @ Tag::Unknown(_) => Ok(Token::Unknown(t, Some(p))), + t @ Tag::Private(_) => Ok(Token::Unknown(t, Some(p))), + _ => Err(p), } } } diff --git a/openpgp/src/cert/parser/mod.rs b/openpgp/src/cert/parser/mod.rs index e031ec48..f7b3289a 100644 --- a/openpgp/src/cert/parser/mod.rs +++ b/openpgp/src/cert/parser/mod.rs @@ -792,21 +792,47 @@ impl<'a> CertParser<'a> { self.packets.push(pk); } - let packets = orig.packets.len(); - t!("Finalizing certificate with {} packets", packets); - let tokens = orig.packets - .into_iter() - .filter_map(|p| p.into()) - .collect::<Vec<Token>>(); - t!("{} tokens: {:?}", tokens.len(), tokens); - if tokens.len() != packets { + let n_packets = orig.packets.len(); + t!("Finalizing certificate with {} packets", n_packets); + + // Convert to tokens, but preserve packets if it fails. + use std::convert::TryInto; + let mut failed = false; + let mut packets: Vec<Packet> = Vec::with_capacity(0); + let mut tokens: Vec<Token> = Vec::with_capacity(n_packets); + for p in orig.packets { + if failed { + // Just stash the packet. + packets.push(p); + } else { + match p.try_into() { + Ok(t) => tokens.push(t), + Err(p) => { + // Conversion failed. Revert the whole process. + packets.reserve(n_packets); + for t in tokens.drain(..) { + packets.push({ + let p: Option<Packet> = t.into(); + p.expect("token created with packet") + }); + } + packets.push(p); + failed = true; + }, + } + } + } + + if failed { // There was at least one packet that doesn't belong in a // Cert. Fail now. - let err = Error::UnsupportedCert( - "Packet sequence includes non-Cert packets.".into()); + let err = Error::UnsupportedCert2( + "Packet sequence includes non-Cert packets.".into(), + packets); t!("Invalid certificate: {}", err); return Err(err.into()); } + t!("{} tokens: {:?}", tokens.len(), tokens); let certo = match CertLowLevelParser::new() .parse(Lexer::from_tokens(&tokens)) @@ -861,7 +887,7 @@ impl<'a> CertParser<'a> { t!("Returning {:?}, constructed from {} packets", certo.as_ref().map(|c| c.fingerprint()), - packets); + n_packets); Ok(certo) } diff --git a/openpgp/src/lib.rs b/openpgp/src/lib.rs index 11878174..4ea09661 100644 --- a/openpgp/src/lib.rs +++ b/openpgp/src/lib.rs @@ -296,6 +296,11 @@ pub enum Error { /// unsupported format. In particular, Sequoia does not support /// version 3 keys. #[error("Unsupported Cert: {0}")] + UnsupportedCert2(String, Vec<Packet>), + + /// Unsupported Cert, deprecated version. + #[deprecated(since = "1.10.0", note = "Use UnsupportedCert2 instead.")] + #[error("Unsupported Cert: {0}")] UnsupportedCert(String), /// Index out of range. |