summaryrefslogtreecommitdiffstats
path: root/openpgp/src/tpk/grammar.lalrpop
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src/tpk/grammar.lalrpop')
-rw-r--r--openpgp/src/tpk/grammar.lalrpop257
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(_, _),
+ }
+}