diff options
Diffstat (limited to 'openpgp/src/tpk/grammar.lalrpop')
-rw-r--r-- | openpgp/src/tpk/grammar.lalrpop | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/openpgp/src/tpk/grammar.lalrpop b/openpgp/src/tpk/grammar.lalrpop new file mode 100644 index 00000000..a89b3d9b --- /dev/null +++ b/openpgp/src/tpk/grammar.lalrpop @@ -0,0 +1,257 @@ +// -*- mode: Rust; -*- + +use Error; +use Signature; +use UserID; +use UserAttribute; +use Key; +use Unknown; +use Packet; +use TPK; + +use tpk::lexer; +use tpk::lexer::{Token, Component}; +use tpk::{SubkeyBinding, UserIDBinding, UserAttributeBinding, UnknownBinding}; + +use lalrpop_util::ParseError; + +grammar; + +// The parser is used in two ways: it can either be used to check +// whether a sequence of packets forms a TPK, or to build a TPK from a +// sequence of packets. In the former case, we only need the packet +// tags; in the latter case, we also need the packets. To handle both +// situations, the token includes the tag and an optional packet. +// When invoking the parser, it is essential, that either *all* tokens +// have no packet, or they all have a packet; mixing the two types of +// tokens will result in a crash. + +pub TPK: Option<TPK> = { + <p:Primary> <c:OptionalComponents> =>? { + match p { + Some((Packet::PublicKey(key), _sigs)) + | Some((Packet::SecretKey(key), _sigs)) => { + let c = c.unwrap(); + + let mut tpk = TPK { + primary: key, + subkeys: vec![], + userids: vec![], + user_attributes: vec![], + unknowns: vec![], + }; + + for c in c.into_iter() { + match c { + Component::SubkeyBinding(b) => + tpk.subkeys.push(b), + Component::UserIDBinding(b) => + tpk.userids.push(b), + Component::UserAttributeBinding(b) => + tpk.user_attributes.push(b), + Component::UnknownBinding(b) => + tpk.unknowns.push(b), + } + } + + Ok(Some(tpk)) + } + Some((Packet::Unknown(_unknown), _sigs)) => { + Err(ParseError::User { + error: Error::UnsupportedTPK( + "Unsupported primary key.".into()) + }) + } + None => { + // Just validating a message... + assert!(c.is_none() || c.unwrap().len() == 0); + Ok(None) + } + _ => unreachable!(), + } + } +}; + +Primary: Option<(Packet, Vec<Signature>)> = { + <pk:PrimaryKey> <sigs:OptionalSignatures> => { + if let Some(pk) = pk { + Some((pk, sigs.unwrap())) + } else { + // Just validating a message... + assert!(sigs.is_none() || sigs.unwrap().len() == 0); + None + } + } +} + +PrimaryKey: Option<Packet> = { + <t:PUBLIC_KEY> => t.into(), + <t:SECRET_KEY> => t.into(), +}; + +OptionalSignatures: Option<Vec<Signature>> = { + => Some(vec![]), + <sigs:OptionalSignatures> <sig:SIGNATURE> => { + match sig { + Token::Signature(Some(Packet::Signature(sig))) => { + assert!(sigs.is_some()); + let mut sigs = sigs.unwrap(); + + sigs.push(sig); + Some(sigs) + } + Token::Signature(Some(Packet::Unknown(_sig))) => { + // Ignore unsupported / bad signatures. + assert!(sigs.is_some()); + sigs + } + // Just validating a message... + Token::Signature(None) => return None, + _ => unreachable!(), + } + } +} + +OptionalComponents: Option<Vec<Component>> = { + => Some(vec![]), + <cs:OptionalComponents> <c:Component> => { + if let Some(c) = c { + let mut cs = cs.unwrap(); + cs.push(c); + Some(cs) + } else { + // Just validating a message... + None + } + }, +} + +Component: Option<Component> = { + <key:Subkey> <sigs:OptionalSignatures> => { + match key { + Some(key) => { + let sigs = sigs.unwrap(); + + Some(Component::SubkeyBinding(SubkeyBinding { + subkey: key, + selfsigs: vec![], + certifications: sigs, + })) + }, + // Just validating a message... + None => None, + } + }, + <u:UserID> <sigs:OptionalSignatures> => { + match u { + Some(u) => { + let sigs = sigs.unwrap(); + + Some(Component::UserIDBinding(UserIDBinding { + userid: u, + selfsigs: vec![], + certifications: sigs, + })) + }, + // Just validating a message... + None => None, + } + }, + <u:UserAttribute> <sigs:OptionalSignatures> => { + match u { + Some(u) => { + let sigs = sigs.unwrap(); + + Some(Component::UserAttributeBinding(UserAttributeBinding { + user_attribute: u, + selfsigs: vec![], + certifications: sigs, + })) + }, + // Just validating a message... + None => None, + } + }, + <u:Unknown> <sigs:OptionalSignatures> => { + match u { + Some(u) => { + let sigs = sigs.unwrap(); + + Some(Component::UnknownBinding(UnknownBinding { + unknown: u, + sigs: sigs, + })) + }, + // Just validating a message... + None => None, + } + }, +} + +Subkey: Option<Key> = { + <t:PUBLIC_SUBKEY> => { + match t.into() { + Some(Packet::PublicSubkey(key)) => Some(key), + // Just validating a message... + None => None, + _ => unreachable!(), + } + }, + <t:SECRET_SUBKEY> => { + match t.into() { + Some(Packet::SecretSubkey(key)) => Some(key), + // Just validating a message... + None => None, + _ => unreachable!(), + } + }, +} + +UserID: Option<UserID> = { + <t:USERID> => { + match t.into() { + Some(Packet::UserID(u)) => Some(u), + // Just validating a message... + None => None, + _ => unreachable!(), + } + }, +} + +UserAttribute: Option<UserAttribute> = { + <t:USER_ATTRIBUTE> => { + match t.into() { + Some(Packet::UserAttribute(u)) => Some(u), + // Just validating a message... + None => None, + _ => unreachable!(), + } + }, +} + +Unknown: Option<Unknown> = { + <t:UNKNOWN> => { + match t.into() { + Some(Packet::Unknown(u)) => Some(u), + // Just validating a message... + None => None, + _ => unreachable!(), + } + }, +} + +extern { + type Location = usize; + type Error = Error; + + enum lexer::Token { + PUBLIC_KEY => lexer::Token::PublicKey(_), + SECRET_KEY => lexer::Token::SecretKey(_), + PUBLIC_SUBKEY => lexer::Token::PublicSubkey(_), + SECRET_SUBKEY => lexer::Token::SecretSubkey(_), + USERID => lexer::Token::UserID(_), + USER_ATTRIBUTE => lexer::Token::UserAttribute(_), + SIGNATURE => lexer::Token::Signature(_), + UNKNOWN => lexer::Token::Unknown(_, _), + } +} |