use std::convert::TryFrom;
use std::fmt;
use std::io;
use std::path::Path;
use crate::Result;
use crate::Error;
use crate::Packet;
use crate::PacketPile;
use crate::packet::Literal;
use crate::packet::Tag;
use crate::parse::Parse;
mod lexer;
lalrpop_util::lalrpop_mod!(#[allow(clippy::all)] grammar, "/message/grammar.rs");
use self::lexer::{Lexer, LexicalError};
pub use self::lexer::Token;
use lalrpop_util::ParseError;
use self::grammar::MessageParser;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum MessageParserError {
Parser(ParseError<usize, Token, LexicalError>),
OpenPGP(Error),
}
assert_send_and_sync!(MessageParserError);
impl From<MessageParserError> for anyhow::Error {
fn from(err: MessageParserError) -> Self {
match err {
MessageParserError::Parser(p) => p.into(),
MessageParserError::OpenPGP(p) => p.into(),
}
}
}
#[derive(Debug)]
pub(crate) enum MessageValidity {
Message,
MessagePrefix,
Error(anyhow::Error),
}
#[allow(unused)]
impl MessageValidity {
pub fn is_message(&self) -> bool {
if let MessageValidity::Message = self {
true
} else {
false
}
}
pub fn is_message_prefix(&self) -> bool {
if let MessageValidity::MessagePrefix = self {
true
} else {
false
}
}
pub fn is_err(&self) -> bool {
if let MessageValidity::Error(_) = self {
true
} else {
false
}
}
}
#[derive(Debug)]
pub(crate) struct MessageValidator {
tokens: Vec<Token>,
finished: bool,
depth: Option<isize>,
error: Option<MessageParserError>,
}
impl Default for MessageValidator {
fn default() -> Self {
MessageValidator::new()
}
}
impl MessageValidator {
pub fn new() -> Self {
MessageValidator {
tokens: vec![],
finished: false,
depth: Some(0),
error: None,
}
}
#[cfg(test)]
pub(crate) fn push_raw(&mut self, token: Token) {
assert!(!self.finished);
if self.error.is_some() {
return;
}
self.depth = None;
self.tokens.push(token);
}
pub fn push_token(&mut self, token: Token, path: &[usize]) {
assert!(!self.finished);
assert!(self.depth.is_some());
assert!(token != Token::Pop);
assert!(path.len() > 0);
if self.error.is_some() {
return;
}
let depth = path.len() as isize - 1;
if self.depth.unwrap() > depth {
for _ in 1..self.depth.unwrap() - depth + 1 {
self.tokens.push(Token::Pop);
}
}
self.depth = Some(depth);
self.tokens.push(token);
}
pub fn push(&mut self, tag: Tag, path: &[usize]) {
if self.error.is_some() {
return;
}
let token = match tag {
Tag::Literal => Token::Literal,
Tag::CompressedData => Token::CompressedData,
Tag::SKESK => Token::SKESK,
Tag::PKESK => Token::PKESK,
Tag::SEIP => Token::SEIP,
Tag::MDC => Token::MDC,
Tag::AED => Token::AED,
Tag::OnePassSig => Token::OPS,
Tag::Signature => Token::SIG,
Tag::Marker => {
return;
},
_ => {
self.error = Some(MessageParserError::OpenPGP(
Error::MalformedMessage(
format!("Invalid OpenPGP message: \
{:?} packet (at {:?}) not expected",
tag, path).into())));
self.tokens.clear();
return;
}
};
self.push_token(token, path)
}
pub fn finish(&mut self) {
assert!(!self.finished);
if let Some(depth) = self.depth {
for _ in 0..depth {
self.tokens.push(Token::Pop);
}
}
self.finished = true;
}
pub fn check(&self) -> MessageValidity {
if let Some(ref err) = self.error {
return MessageValidity::Error((*err).clone().into());
}
let r = MessageParser::new().parse(
Lexer::from_tokens(&self.tokens[..]));
if self.finished {
match r {
Ok(_) => MessageValidity::Message,
Err(ref err) =>
MessageValidity::Error(
MessageParserError::Parser((*err).clone()).into()),
}
} else {
match r {
Ok(_) => MessageValidity::MessagePrefix,
Err(ParseError::UnrecognizedEOF { .. }) =>
MessageValidity::MessagePrefix,
Err(ref err) =>
MessageValidity::Error(
MessageParserError::Parser((*err).clone()).into()),
}
}
}
}
#[derive(PartialEq)]
pub struct Message {
pile: PacketPile,
}
assert_send_and_sync!(Message);
impl fmt::Debug for Message {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Message")
.field("pile", &self.pile)
.finish()
}
}
impl<'a> Parse<'a, Message> for Message {
fn from_reader<R: 'a + io::Read + Send + Sync>(reader: R) -> Result<Self> {
Self::try_from(PacketPile::from_reader(reader)?)
}
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
Self::try_from(PacketPile::from_file(path)?)
}
fn from_bytes<D: AsRef<[u8]> + ?Sized + Send + Sync>(data: &'a D) -> Result<Self> {
Self::try_from(PacketPile::from_bytes(data)?)
}
}
impl std::str::FromStr for Message {
type Err = anyhow::Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Self::from_bytes(s.as_bytes())
}
}
impl Message {
pub fn body(&self) -> Option<&Literal> {
for packet in self.pile.descendants() {
if let &Packet::Literal(ref l) = packet {
return Some(l);
}
}
None
}
}
impl TryFrom<PacketPile> for Message {
type Error = anyhow::Error;
fn try_from(pile: PacketPile) -> Result<Self> {
let mut v = MessageValidator::new();
for (mut path, packet) in pile.descendants().paths() {
match packet {
Packet::Unknown(ref u) =>
return Err(MessageParserError::OpenPGP(
Error::MalformedMessage(
format!("Invalid OpenPGP message: \
{:?} packet (at {:?}) not expected: {}",
u.tag(), path, u.error()).into()))
.into()),
_ => v.push(packet.tag(), &path),
}
match packet {
Packet::CompressedData(_) | Packet::SEIP(_) | Packet::AED(_) =>
{
path.push(0);
if packet.children().is_none() {
v.push_token(Token::OpaqueContent, &path);
}
}
_ => {}
}
}
v.finish();
match v.check() {
MessageValidity::Message => Ok(Message { pile }),
MessageValidity::MessagePrefix => unreachable!(),
MessageValidity::Error(e) => Err(e.into()),
}
}
}
impl TryFrom<Vec<Packet>> for Message {
type Error = anyhow::Error;
fn try_from(packets: Vec<Packet>) -> Result<Self> {
Self::try_from(PacketPile::from(packets))
}
}
impl From<Message> for PacketPile {
fn from(m: Message) -> Self {
m.pile
}
}
impl ::std::ops::Deref for Message {
type Target = PacketPile;
fn deref(&self) -> &Self::Target {
&self.pile
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::DataFormat::Text;
use crate::HashAlgorithm;
use crate::types::CompressionAlgorithm;
use crate::SymmetricAlgorithm;
use crate::PublicKeyAlgorithm;
use crate::SignatureType;
use crate::crypto::S2K;
use crate::crypto::mpi::{Ciphertext, MPI};
use crate::packet::prelude::*;
#[test]
fn tokens() {
use self::lexer::{Token, Lexer};
use self::lexer::Token::*;
use self::grammar::MessageParser;
struct TestVector<'a> {
s: &'a [Token],
result: bool,
}
let test_vectors = [
TestVector {
s: &[Literal][..],
result: true,
},
TestVector {
s: &[CompressedData, Literal, Pop],
result: true,
},
TestVector {
s: &[CompressedData, CompressedData, Literal,
Pop, Pop],
result: true,
},
TestVector {
s: &[SEIP, Literal, MDC, Pop],
result: true,
},
TestVector {
s: &[CompressedData, SEIP, Literal, MDC, Pop, Pop],
result: true,
},
TestVector {
s: &[CompressedData, SEIP, CompressedData, Literal,
Pop, MDC, Pop, Pop],
result: true,
},
TestVector {
s: &[SEIP, MDC, Pop],
result: false,
},
TestVector {
s: &[SKESK, SEIP, Literal, MDC, Pop],
result: true,
},
TestVector {
s: &[PKESK, SEIP, Literal, MDC, Pop],
result: true,
},
TestVector {
s: &[SKESK, SKESK, SEIP, Literal, MDC, Pop],
result: true,
},
TestVector {
s: &[AED, Literal, Pop],
result: true,
},
TestVector {
s: &[CompressedData, AED, Literal, Pop, Pop],
result: true,
},
TestVector {
s: &[CompressedData, AED, CompressedData, Literal,
Pop, Pop, Pop],
result: true,
},
TestVector {
s: &[AED, Pop],
result: false,
},
TestVector {
s: &[SKESK, AED, Literal, Pop],
result: true,
},
TestVector {
s: &[PKESK, AED, Literal, Pop],
result: true,
},
TestVector {
s: &[SKESK, SKESK, AED, Literal, Pop],
result: true,
},
TestVector {
s: &[OPS, Literal, SIG],
result: true,
},
TestVector {
s: &[OPS, OPS, Literal, SIG, SIG],
result: true,
},
TestVector {
s: &[OPS, OPS, Literal, SIG],
result: false,
},
TestVector {
s: &[OPS, OPS, SEIP, OPS, SEIP, Literal, MDC, Pop,
SIG, MDC, Pop, SIG, SIG],
result: true,
},
TestVector {
s: &[CompressedData, OpaqueContent],
result: false,
},
TestVector {
s: &[CompressedData, OpaqueContent, Pop],
result: true,
},
TestVector {
s: &[CompressedData, CompressedData, OpaqueContent, Pop, Pop],
result: true,
},
TestVector {
s: &[SEIP, CompressedData, OpaqueContent, Pop, MDC, Pop],
result: true,
},
TestVector {
s: &[SEIP, OpaqueContent, Pop],
result: true,
},
];
for v in &test_vectors {
if v.result {
let mut l = MessageValidator::new();
for token in v.s.iter() {
l.push_raw(*token);
assert_match!(MessageValidity::MessagePrefix = l.check());
}
l.finish();
assert_match!(MessageValidity::Message = l.check());
}
match MessageParser::new().parse(Lexer::from_tokens(v.s)) {
Ok(r) => assert!(v.result, "Parsing: {:?} => {:?}", v.s, r),
Err(e) => assert!(! v.result, "Parsing: {:?} => {:?}", v.s, e),
}
}
}
#[test]
fn tags() {
use crate::packet::Tag::*;
struct TestVector<'a> {
s: &'a [(Tag, isize)],
result: bool,
}
let test_vectors = [
TestVector {
s: &[(Literal, 0)][..],
result: true,
},
TestVector {
s: &[(CompressedData, 0), (Literal, 1)],
result: true,
},
TestVector {
s: &[(CompressedData, 0), (CompressedData, 1), (Literal, 2)],
result: true,
},
TestVector {
s: &[(SEIP, 0), (Literal, 1), (MDC, 1)],
result: true,
},
TestVector {
s: &[(CompressedData, 0), (SEIP, 1), (Literal, 2), (MDC, 2)],
result: true,
},
TestVector {
s: &[(CompressedData, 0), (SEIP, 1),
(CompressedData, 2), (Literal, 3), (MDC, 2)],
result: true,
},
TestVector {
s: &[(CompressedData, 0), (SEIP, 1),
(CompressedData, 2), (Literal, 3), (MDC, 3)],
result: false,
},
TestVector {
s: &[(SEIP, 0), (MDC, 0)],
result: false,
},
TestVector {
s: &[(SKESK, 0), (SEIP, 0), (Literal, 1), (MDC, 1)],
result: true,
},
TestVector {
s: &[(PKESK, 0), (SEIP, 0), (Literal, 1), (MDC, 1)],
result: true,
},
TestVector {
s: &[(PKESK, 0), (SEIP, 0), (CompressedData, 1), (Literal, 2),
(MDC, 1)],
result: true,
},
TestVector {
s: &[(SKESK, 0), (SKESK, 0), (SEIP, 0), (Literal, 1), (MDC, 1)],
result: true,
},
TestVector {
s: &[(OnePassSig, 0), (Literal, 0), (Signature, 0)],
result: true,
},
TestVector {
s: &[(OnePassSig, 0), (CompressedData, 0), (Literal, 1),
(Signature, 0)],
result: true,
},
TestVector {
s: &[(OnePassSig, 0), (OnePassSig, 0), (Literal, 0),
(Signature, 0), (Signature, 0)],
result: true,
},
TestVector {
s: &[(OnePassSig, 0), (OnePassSig, 0), (Literal, 0),
(Signature, 0)],
result: false,
},
TestVector {
s: &[(OnePassSig, 0), (OnePassSig, 0), (SEIP, 0),
(OnePassSig, 1), (SEIP, 1), (Literal, 2), (MDC, 2),
(Signature, 1), (MDC, 1), (Signature, 0), (Signature, 0)],
result: true,
},
TestVector {
s: &[(Marker, 0),
(OnePassSig, 0), (Literal, 0), (Signature, 0)],
result: true,
},
];
for v in &test_vectors {
let mut l = MessageValidator::new();
for (token, depth) in v.s.iter() {
l.push(*token,
&(0..1 + *depth)
.map(|x| x as usize)
.collect::<Vec<_>>()[..]);
if v.result {
assert_match!(MessageValidity::MessagePrefix = l.check());
}
}
l.finish();
if v.result {
assert_match!(MessageValidity::Message = l.check());
} else {
assert_match!(MessageValidity::Error(_) = l.check());
}
}
}
#[test]
fn basic() {
let message = Message::try_from(vec![]);
assert!(message.is_err(), "{:?}", message);
let mut packets = Vec::new();
let mut lit = Literal::new(Text);
lit.set_body(b"data".to_vec());
packets.push(lit.into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
}
#[test]
fn compressed_part() {
let mut lit = Literal::new(Text);
lit.set_body(b"data".to_vec());
let mut packets = Vec::new();
packets.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(lit.clone().into())
.into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
let mut packets = Vec::new();
packets.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(lit.clone().into())
.push(lit.clone().into())
.into());
let message = Message::try_from(packets);
assert!(message.is_err(), "{:?}", message);
let mut packets = Vec::new();
packets.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(lit.clone().into())
.into());
packets.push(lit.clone().into());
let message = Message::try_from(packets);
assert!(message.is_err(), "{:?}", message);
let mut packets = Vec::new();
packets.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(lit.clone()
.into())
.into())
.into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
}
#[test]
fn one_pass_sig_part() {
let mut lit = Literal::new(Text);
lit.set_body(b"data".to_vec());
let hash = crate::types::HashAlgorithm::SHA512;
let key: key::SecretKey =
crate::packet::key::Key4::generate_ecc(true, crate::types::Curve::Ed25519)
.unwrap().into();
let mut pair = key.clone().into_keypair().unwrap();
let sig = crate::packet::signature::SignatureBuilder::new(SignatureType::Binary)
.sign_hash(&mut pair, hash.context().unwrap()).unwrap();
let mut packets : Vec<Packet> = Vec::new();
packets.push(OnePassSig3::new(SignatureType::Binary).into());
let message = Message::try_from(packets);
assert!(message.is_err(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(lit.clone().into());
let message = Message::try_from(packets);
assert!(message.is_err(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(lit.clone().into());
packets.push(sig.clone().into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(lit.clone().into());
packets.push(sig.clone().into());
packets.push(sig.clone().into());
let message = Message::try_from(packets);
assert!(message.is_err(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(lit.clone().into());
packets.push(sig.clone().into());
packets.push(sig.clone().into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(lit.clone().into());
packets.push(lit.clone().into());
packets.push(sig.clone().into());
packets.push(sig.clone().into());
let message = Message::try_from(packets);
assert!(message.is_err(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(OnePassSig3::new(SignatureType::Binary).into());
packets.push(
CompressedData::new(CompressionAlgorithm::Uncompressed)
.push(lit.clone().into())
.into());
packets.push(sig.clone().into());
packets.push(sig.clone().into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
}
#[test]
fn signature_part() {
let mut lit = Literal::new(Text);
lit.set_body(b"data".to_vec());
let hash = crate::types::HashAlgorithm::SHA512;
let key: key::SecretKey =
crate::packet::key::Key4::generate_ecc(true, crate::types::Curve::Ed25519)
.unwrap().into();
let mut pair = key.clone().into_keypair().unwrap();
let sig = crate::packet::signature::SignatureBuilder::new(SignatureType::Binary)
.sign_hash(&mut pair, hash.context().unwrap()).unwrap();
let mut packets : Vec<Packet> = Vec::new();
packets.push(sig.clone().into());
let message = Message::try_from(packets);
assert!(message.is_err(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(sig.clone().into());
packets.push(lit.clone().into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
let mut packets : Vec<Packet> = Vec::new();
packets.push(sig.clone().into());
packets.push(sig.clone().into());
packets.push(lit.clone().into());
let message = Message::try_from(packets);
assert!(message.is_ok(), "{:?}", message);
}
#[test]
fn encrypted_part() {
let mut lit = Literal::new(Text);
lit.set_body(b"data".to_vec());
let mut packets : Vec<Packet> = Vec::new();
let cipher = SymmetricAlgorithm::AES256;
let sk = crate::crypto::SessionKey::new(cipher.key_size().unwrap());
#[allow(deprecated)]
packets.push(SKESK4::with_password(
cipher,
cipher,
S2K::Simple { hash: HashAlgorithm::SHA256 },
&sk,
&"12345678".into()).unwrap().into());
let message = Message::try_from(packets.clone());
assert!(message.is_err(), "{:?}", message);
packets.push(lit.clone().into());
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::Literal ]);
let message = Message::try_from(packets.clone());
assert!(message.is_err(), "{:?}", message);
let mut seip = SEIP1::new();
seip.children_mut().unwrap().push(
lit.clone().into());
seip.children_mut().unwrap().push(
MDC::from([0u8; 20]).into());
packets[1] = seip.into();
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::SEIP ]);
let message = Message::try_from(packets.clone());
assert!(message.is_ok(), "{:#?}", message);
let skesk = packets[0].clone();
packets.push(skesk);
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::SEIP, Tag::SKESK ]);
let message = Message::try_from(packets.clone());
assert!(message.is_err(), "{:#?}", message);
packets.swap(1, 2);
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::SKESK, Tag::SEIP ]);
let message = Message::try_from(packets.clone());
assert!(message.is_ok(), "{:#?}", message);
let seip = packets[2].clone();
packets.push(seip);
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::SKESK, Tag::SEIP, Tag::SEIP ]);
let message = Message::try_from(packets.clone());
assert!(message.is_err(), "{:#?}", message);
packets[3] = lit.clone().into();
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::SKESK, Tag::SEIP, Tag::Literal ]);
let message = Message::try_from(packets.clone());
assert!(message.is_err(), "{:#?}", message);
packets.remove(3);
packets[2].container_mut().unwrap()
.children_mut().unwrap().push(lit.clone().into());
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::SKESK, Tag::SEIP ]);
let message = Message::try_from(packets.clone());
assert!(message.is_err(), "{:#?}", message);
packets[2].container_mut().unwrap()
.children_mut().unwrap().pop().unwrap();
#[allow(deprecated)]
packets.insert(
1,
PKESK3::new(
"0000111122223333".parse().unwrap(),
PublicKeyAlgorithm::RSAEncrypt,
Ciphertext::RSA { c: MPI::new(&[]) }).unwrap().into());
assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
== [ Tag::SKESK, Tag::PKESK, Tag::SKESK, Tag::SEIP ]);
let message = Message::try_from(packets.clone());
assert!(message.is_ok(), "{:#?}", message);
}
#[test]
fn basic_message_validator() {
use crate::message::{MessageValidator, MessageValidity, Token};
let mut l = MessageValidator::new();
l.push_token(Token::Literal, &[0]);
l.finish();
assert!(if let MessageValidity::Message = l.check() { true } else { false });
}
#[test]
fn message_validator_push_token() {
use crate::message::{MessageValidator, MessageValidity, Token};
let mut l = MessageValidator::new();
l.push_token(Token::Literal, &[0]);
l.finish();
assert!(if let MessageValidity::Message = l.check() { true } else { false });
}
#[test]
fn message_validator_push() {
use crate::message::{MessageValidator, MessageValidity};
use crate::packet::Tag;
let mut l = MessageValidator::new();
l.push(Tag::Literal, &[0]);
l.finish();
assert!(if let MessageValidity::Message = l.check() { true } else { false });
}
#[test]
fn message_validator_finish() {
use crate::message::{MessageValidator, MessageValidity};
let mut l = MessageValidator::new();
l.finish();
assert!(if let MessageValidity::Error(_) = l.check() { true } else { false });
}
#[test]
fn message_validator_check() {
use crate::message::{MessageValidator, MessageValidity};
use crate::packet::Tag;
let mut l = MessageValidator::new();
assert!(if let MessageValidity::MessagePrefix = l.check() { true } else { false });
l.finish();
assert!(if let MessageValidity::Error(_) = l.check() { true } else { false });
let mut l = MessageValidator::new();
l.push(Tag::Literal, &[0]);
assert!(if let MessageValidity::MessagePrefix = l.check() { true } else { false });
l.finish();
assert!(if let MessageValidity::Message = l.check() { true } else { false });
}
}