sequoia-openpgp 0.16.0

OpenPGP data types and associated machinery
Documentation
// -*- mode: Rust; -*-

use crate::Error;
use crate::packet::Signature;
use crate::packet::UserID;
use crate::packet::UserAttribute;
use crate::packet::{key, Key};
use crate::packet::Unknown;
use crate::Packet;
use crate::cert::prelude::*;

use crate::cert::parser::low_level::lexer;
use crate::cert::parser::low_level::lexer::{Token, Component};
use crate::cert::ComponentBundles;
use crate::cert::bundle::{
    PrimaryKeyBundle,
    SubkeyBundle,
    UserIDBundle,
    UserAttributeBundle,
    UnknownBundle,
};

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 Cert, or to build a Cert 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 Cert: Option<Cert> = {
    <p:Primary> <c:OptionalComponents> =>? {
        match p {
            Some((Packet::PublicKey(_), _))
            | Some((Packet::SecretKey(_), _)) => {
                let (key, sigs) = match p {
                    Some((Packet::PublicKey(key), sigs)) => (key, sigs),
                    Some((Packet::SecretKey(key), sigs)) => (key.into(), sigs),
                    _ => unreachable!(),
                };
                let c = c.unwrap();

                let mut cert = Cert {
                    primary: PrimaryKeyBundle {
                        component: key,
                        self_signatures: vec![],
                        certifications: sigs,
                        self_revocations: vec![],
                        other_revocations: vec![],
                    },
                    subkeys: ComponentBundles::new(),
                    userids: ComponentBundles::new(),
                    user_attributes: ComponentBundles::new(),
                    unknowns: ComponentBundles::new(),
                    bad: vec![],
                };

                for c in c.into_iter() {
                    match c {
                        Component::SubkeyBundle(b) =>
                            cert.subkeys.push(b),
                        Component::UserIDBundle(b) =>
                            cert.userids.push(b),
                        Component::UserAttributeBundle(b) =>
                            cert.user_attributes.push(b),
                        Component::UnknownBundle(b) =>
                            cert.unknowns.push(b),
                    }
                }

                Ok(Some(cert))
            }
            Some((Packet::Unknown(unknown), _sigs)) => {
                Err(ParseError::User {
                    error: Error::UnsupportedCert(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),
        }
    },

    // A trust packet can go wherever a signature can go, but they
    // are ignored.
    <OptionalSignatures> TRUST,
}

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::SubkeyBundle(SubkeyBundle {
                    component: key,
                    self_signatures: 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::UserIDBundle(UserIDBundle {
                    component: u,
                    self_signatures: 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::UserAttributeBundle(UserAttributeBundle {
                    component: u,
                    self_signatures: 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::UnknownBundle(UnknownBundle {
                    component: u,
                    self_signatures: vec![],
                    certifications: sigs,
                    self_revocations: vec![],
                    other_revocations: vec![],
                }))
            },
            // Just validating a message...
            None => None,
        }
    },
}

Subkey: Option<Key<key::PublicParts, key::SubordinateRole>> = {
    <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.parts_into_public()),
            // 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(_),
        TRUST => lexer::Token::Trust(_),
        UNKNOWN => lexer::Token::Unknown(_, _),
    }
}