sequoia-openpgp 0.6.0

OpenPGP data types and associated machinery
// -*- 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(_, _),
    }
}