// -*- mode: Rust; -*-
use Error;
use packet::Signature;
use packet::UserID;
use packet::UserAttribute;
use packet::Key;
use packet::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,
primary_selfsigs: vec![],
primary_certifications: sigs,
primary_self_revocations: vec![],
primary_other_revocations: vec![],
subkeys: vec![],
userids: vec![],
user_attributes: vec![],
unknowns: vec![],
bad: 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(format!(
"Unsupported primary key: Unparsable {} ({:?}).",
unknown.tag(), unknown).into())
})
}
None => {
// Just validating a message...
assert!(c.is_none() || c.unwrap().len() == 0);
Ok(None)
}
Some((pkt, _)) =>
unreachable!("Expected key or unknown packet, got {:?}", pkt),
}
}
};
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,
tok => unreachable!("Expected signature token, got {:?}", tok),
}
}
}
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,
self_revocations: vec![],
other_revocations: vec![],
}))
},
// 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,
self_revocations: vec![],
other_revocations: vec![],
}))
},
// 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,
self_revocations: vec![],
other_revocations: vec![],
}))
},
// 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,
Some(pkt) =>
unreachable!("Expected public subkey packet, got {:?}", pkt),
}
},
<t:SECRET_SUBKEY> => {
match t.into() {
Some(Packet::SecretSubkey(key)) => Some(key),
// Just validating a message...
None => None,
Some(pkt) =>
unreachable!("Expected secret subkey packet, got {:?}", pkt),
}
},
}
UserID: Option<UserID> = {
<t:USERID> => {
match t.into() {
Some(Packet::UserID(u)) => Some(u),
// Just validating a message...
None => None,
Some(pkt) =>
unreachable!("Expected user id packet, got {:?}", pkt),
}
},
}
UserAttribute: Option<UserAttribute> = {
<t:USER_ATTRIBUTE> => {
match t.into() {
Some(Packet::UserAttribute(u)) => Some(u),
// Just validating a message...
None => None,
Some(pkt) =>
unreachable!("Expected user attribute packet, got {:?}", pkt),
}
},
}
Unknown: Option<Unknown> = {
<t:UNKNOWN> => {
match t.into() {
Some(Packet::Unknown(u)) => Some(u),
// Just validating a message...
None => None,
Some(pkt) =>
unreachable!("Expected unknown packet, got {:?}", pkt),
}
},
}
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(_, _),
}
}