use std::fmt;
use std::ops::{Deref, DerefMut};
use std::slice;
use std::vec;
use std::io;
use Result;
use Packet;
pub mod ctb;
use self::ctb::{CTB, PacketLengthType};
use buffered_reader::BufferedReader;
mod tag;
pub use self::tag::Tag;
mod unknown;
pub use self::unknown::Unknown;
pub mod signature;
pub use self::signature::Signature;
mod one_pass_sig;
pub use self::one_pass_sig::OnePassSig;
pub(crate) mod key;
pub use self::key::Key;
mod userid;
pub use self::userid::UserID;
mod user_attribute;
pub use self::user_attribute::UserAttribute;
mod literal;
pub use self::literal::Literal;
mod compressed_data;
pub use self::compressed_data::CompressedData;
mod seip;
pub use self::seip::SEIP;
mod skesk;
pub use self::skesk::{SKESK, SKESK4, SKESK5};
mod pkesk;
pub use self::pkesk::PKESK;
mod mdc;
pub use self::mdc::MDC;
mod aed;
pub use self::aed::AED;
impl<'a> Deref for Packet {
type Target = Common;
fn deref(&self) -> &Self::Target {
match self {
&Packet::Unknown(ref packet) => &packet.common,
&Packet::Signature(ref packet) => &packet.common,
&Packet::OnePassSig(ref packet) => &packet.common,
&Packet::PublicKey(ref packet) => &packet.common,
&Packet::PublicSubkey(ref packet) => &packet.common,
&Packet::SecretKey(ref packet) => &packet.common,
&Packet::SecretSubkey(ref packet) => &packet.common,
&Packet::UserID(ref packet) => &packet.common,
&Packet::UserAttribute(ref packet) => &packet.common,
&Packet::Literal(ref packet) => &packet.common,
&Packet::CompressedData(ref packet) => &packet.common,
&Packet::PKESK(ref packet) => &packet.common,
&Packet::SKESK(SKESK::V4(ref packet)) => &packet.common,
&Packet::SKESK(SKESK::V5(ref packet)) => &packet.skesk4.common,
&Packet::SEIP(ref packet) => &packet.common,
&Packet::MDC(ref packet) => &packet.common,
&Packet::AED(ref packet) => &packet.common,
}
}
}
impl<'a> DerefMut for Packet {
fn deref_mut(&mut self) -> &mut Common {
match self {
&mut Packet::Unknown(ref mut packet) => &mut packet.common,
&mut Packet::Signature(ref mut packet) => &mut packet.common,
&mut Packet::OnePassSig(ref mut packet) => &mut packet.common,
&mut Packet::PublicKey(ref mut packet) => &mut packet.common,
&mut Packet::PublicSubkey(ref mut packet) => &mut packet.common,
&mut Packet::SecretKey(ref mut packet) => &mut packet.common,
&mut Packet::SecretSubkey(ref mut packet) => &mut packet.common,
&mut Packet::UserID(ref mut packet) => &mut packet.common,
&mut Packet::UserAttribute(ref mut packet) => &mut packet.common,
&mut Packet::Literal(ref mut packet) => &mut packet.common,
&mut Packet::CompressedData(ref mut packet) => &mut packet.common,
&mut Packet::PKESK(ref mut packet) => &mut packet.common,
&mut Packet::SKESK(SKESK::V4(ref mut packet)) => &mut packet.common,
&mut Packet::SKESK(SKESK::V5(ref mut packet)) => &mut packet.skesk4.common,
&mut Packet::SEIP(ref mut packet) => &mut packet.common,
&mut Packet::MDC(ref mut packet) => &mut packet.common,
&mut Packet::AED(ref mut packet) => &mut packet.common,
}
}
}
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Clone, Copy)]
pub enum BodyLength {
Full(u32),
Partial(u32),
Indeterminate,
}
impl BodyLength {
pub(crate) fn parse_new_format<T: BufferedReader<C>, C> (bio: &mut T)
-> io::Result<BodyLength>
{
let octet1 : u8 = bio.data_consume_hard(1)?[0];
match octet1 {
0...191 =>
Ok(BodyLength::Full(octet1 as u32)),
192...223 => {
let octet2 = bio.data_consume_hard(1)?[0];
Ok(BodyLength::Full(((octet1 as u32 - 192) << 8)
+ octet2 as u32 + 192))
},
224...254 =>
Ok(BodyLength::Partial(1 << (octet1 & 0x1F))),
255 =>
Ok(BodyLength::Full(bio.read_be_u32()?)),
_ =>
unreachable!(),
}
}
pub(crate) fn parse_old_format<T: BufferedReader<C>, C>
(bio: &mut T, length_type: PacketLengthType)
-> Result<BodyLength>
{
match length_type {
PacketLengthType::OneOctet =>
Ok(BodyLength::Full(bio.data_consume_hard(1)?[0] as u32)),
PacketLengthType::TwoOctets =>
Ok(BodyLength::Full(bio.read_be_u16()? as u32)),
PacketLengthType::FourOctets =>
Ok(BodyLength::Full(bio.read_be_u32()? as u32)),
PacketLengthType::Indeterminate =>
Ok(BodyLength::Indeterminate),
}
}
}
#[test]
fn body_length_new_format() {
use buffered_reader::BufferedReaderMemory;
fn test(input: &[u8], expected_result: BodyLength) {
assert_eq!(
BodyLength::parse_new_format(
&mut BufferedReaderMemory::new(input)).unwrap(),
expected_result);
}
test(&[0x64][..], BodyLength::Full(100));
test(&[0xC5, 0xFB][..], BodyLength::Full(1723));
test(&[0xFF, 0x00, 0x01, 0x86, 0xA0][..], BodyLength::Full(100000));
test(&[0xEF][..], BodyLength::Partial(32768));
test(&[0xE1][..], BodyLength::Partial(2));
test(&[0xF0][..], BodyLength::Partial(65536));
test(&[0xC5, 0xDD][..], BodyLength::Full(1693));
}
#[test]
fn body_length_old_format() {
use buffered_reader::BufferedReaderMemory;
fn test(input: &[u8], plt: PacketLengthType,
expected_result: BodyLength, expected_rest: &[u8]) {
let mut bio = BufferedReaderMemory::new(input);
assert_eq!(BodyLength::parse_old_format(&mut bio, plt).unwrap(),
expected_result);
let rest = bio.data_eof();
assert_eq!(rest.unwrap(), expected_rest);
}
test(&[1], PacketLengthType::OneOctet, BodyLength::Full(1), &b""[..]);
test(&[1, 2], PacketLengthType::TwoOctets,
BodyLength::Full((1 << 8) + 2), &b""[..]);
test(&[1, 2, 3, 4], PacketLengthType::FourOctets,
BodyLength::Full((1 << 24) + (2 << 16) + (3 << 8) + 4), &b""[..]);
test(&[1, 2, 3, 4, 5, 6], PacketLengthType::FourOctets,
BodyLength::Full((1 << 24) + (2 << 16) + (3 << 8) + 4), &[5, 6][..]);
test(&[1, 2, 3, 4], PacketLengthType::Indeterminate,
BodyLength::Indeterminate, &[1, 2, 3, 4][..]);
}
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct Common {
pub children: Option<Container>,
pub body: Option<Vec<u8>>,
}
impl fmt::Debug for Common {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Common")
.field("children", &self.children)
.field("body (bytes)",
&self.body.as_ref().map(|body| body.len()))
.finish()
}
}
impl Default for Common {
fn default() -> Common {
Common {
children: None,
body: None,
}
}
}
impl Common {
pub fn descendants(&self) -> PacketIter {
return PacketIter {
children: if let Some(ref container) = self.children {
container.packets.iter()
} else {
let empty_packet_slice : &[Packet] = &[];
empty_packet_slice.iter()
},
child: None,
grandchildren: None,
depth: 0,
}
}
pub fn body(&self) -> Option<&[u8]> {
self.body.as_ref().map(|b| b.as_slice())
}
pub fn set_body(&mut self, data: Vec<u8>) {
self.children = None;
self.body = Some(data);
}
}
#[derive(Clone, Debug)]
pub struct Header {
pub ctb: CTB,
pub length: BodyLength,
}
#[derive(PartialEq, Eq, Hash, Clone)]
pub struct Container {
pub(crate) packets: Vec<Packet>,
}
impl fmt::Debug for Container {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Container")
.field("packets", &self.packets)
.finish()
}
}
impl Container {
pub(crate) fn new() -> Container {
Container { packets: Vec::with_capacity(8) }
}
pub(crate) fn push(&mut self, packet: Packet) {
self.packets.push(packet);
}
pub(crate) fn insert(&mut self, i: usize, packet: Packet) {
self.packets.insert(i, packet);
}
pub fn descendants(&self) -> PacketIter {
return PacketIter {
children: self.children(),
child: None,
grandchildren: None,
depth: 0,
};
}
pub fn children<'a>(&'a self) -> slice::Iter<'a, Packet> {
self.packets.iter()
}
pub fn into_children(self) -> vec::IntoIter<Packet> {
self.packets.into_iter()
}
fn indent(depth: usize) -> &'static str {
use std::cmp;
let s = " ";
return &s[0..cmp::min(depth, s.len())];
}
pub(crate) fn pretty_print(&self, indent: usize) {
for (i, p) in self.packets.iter().enumerate() {
eprintln!("{}{}: {:?}",
Self::indent(indent), i + 1, p);
if let Some(ref children) = self.packets[i].children {
children.pretty_print(indent + 1);
}
}
}
}
pub struct PacketIter<'a> {
children: slice::Iter<'a, Packet>,
child: Option<&'a Packet>,
grandchildren: Option<Box<PacketIter<'a>>>,
depth: usize,
}
impl<'a> Iterator for PacketIter<'a> {
type Item = &'a Packet;
fn next(&mut self) -> Option<Self::Item> {
if let Some(ref mut grandchildren) = self.grandchildren {
let grandchild = grandchildren.next();
if grandchild.is_some() {
self.depth = grandchildren.depth + 1;
return grandchild;
}
}
self.child = self.children.next();
if let Some(child) = self.child {
self.grandchildren = Some(Box::new(child.descendants()));
}
self.depth = 0;
return self.child;
}
}
impl<'a> PacketIter<'a> {
pub fn paths(self) -> PacketPathIter<'a> {
PacketPathIter {
iter: self,
path: None,
}
}
}
pub struct PacketPathIter<'a> {
iter: PacketIter<'a>,
path: Option<Vec<usize>>,
}
impl<'a> Iterator for PacketPathIter<'a> {
type Item = (Vec<usize>, &'a Packet);
fn next(&mut self) -> Option<Self::Item> {
if let Some(packet) = self.iter.next() {
if self.path.is_none() {
let mut path = Vec::with_capacity(4);
path.push(0);
self.path = Some(path);
} else {
let mut path = self.path.take().unwrap();
let old_depth = path.len() - 1;
let depth = self.iter.depth;
if old_depth > depth {
path.truncate(depth + 1);
path[depth] += 1;
} else if old_depth == depth {
path[old_depth] += 1;
} else if old_depth + 1 == depth {
path.push(0);
}
self.path = Some(path);
}
Some((self.path.as_ref().unwrap().clone(), packet))
} else {
None
}
}
}
#[test]
fn packet_path_iter() {
use std::path::PathBuf;
use PacketPile;
fn path_to(artifact: &str) -> PathBuf {
[env!("CARGO_MANIFEST_DIR"), "tests", "data", "messages", artifact]
.iter().collect()
}
fn paths(iter: slice::Iter<Packet>) -> Vec<Vec<usize>> {
let mut lpaths : Vec<Vec<usize>> = Vec::new();
for (i, packet) in iter.enumerate() {
let mut v = Vec::new();
v.push(i);
lpaths.push(v);
if let Some(ref children) = packet.children {
for mut path in paths(children.packets.iter()).into_iter() {
path.insert(0, i);
lpaths.push(path);
}
}
}
lpaths
}
for i in 1..5 {
let pile = PacketPile::from_file(
path_to(&format!("recursive-{}.gpg", i)[..])).unwrap();
let mut paths1 : Vec<Vec<usize>> = Vec::new();
for path in paths(pile.children()).iter() {
paths1.push(path.clone());
}
let mut paths2 : Vec<Vec<usize>> = Vec::new();
for (path, packet) in pile.descendants().paths() {
assert_eq!(Some(packet), pile.path_ref(&path[..]));
paths2.push(path);
}
if paths1 != paths2 {
eprintln!("PacketPile:");
pile.pretty_print();
eprintln!("Expected paths:");
for p in paths1 {
eprintln!(" {:?}", p);
}
eprintln!("Got paths:");
for p in paths2 {
eprintln!(" {:?}", p);
}
panic!("Something is broken. Don't panic.");
}
}
}