use std::fmt;
use std::hash::Hasher;
use std::ops::{Deref, DerefMut};
use std::slice;
use std::iter::IntoIterator;
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
use crate::Result;
#[macro_use]
mod container;
pub use container::Container;
pub use container::Body;
pub mod prelude;
mod any;
pub use self::any::Any;
mod tag;
pub use self::tag::Tag;
pub mod header;
pub use self::header::Header;
mod unknown;
pub use self::unknown::Unknown;
pub mod signature;
pub mod one_pass_sig;
pub use one_pass_sig::OnePassSig;
pub mod key;
pub use key::Key;
mod marker;
pub use self::marker::Marker;
mod trust;
pub use self::trust::Trust;
mod userid;
pub use self::userid::UserID;
pub 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;
pub mod seip;
pub mod skesk;
pub use skesk::SKESK;
pub mod pkesk;
pub use pkesk::PKESK;
mod mdc;
pub use self::mdc::MDC;
mod padding;
pub use self::padding::Padding;
#[non_exhaustive]
#[derive(PartialEq, Eq, Hash, Clone)]
pub enum Packet {
Unknown(Unknown),
Signature(Signature),
OnePassSig(OnePassSig),
PublicKey(key::PublicKey),
PublicSubkey(key::PublicSubkey),
SecretKey(key::SecretKey),
SecretSubkey(key::SecretSubkey),
Marker(Marker),
Trust(Trust),
UserID(UserID),
UserAttribute(UserAttribute),
Literal(Literal),
CompressedData(CompressedData),
PKESK(PKESK),
SKESK(SKESK),
SEIP(SEIP),
#[deprecated]
MDC(MDC),
Padding(Padding),
}
assert_send_and_sync!(Packet);
macro_rules! impl_into_iterator {
($t:ty) => {
impl_into_iterator!($t where);
};
($t:ty where $( $w:ident: $c:path ),*) => {
impl<$($w),*> IntoIterator for $t
where $($w: $c ),*
{
type Item = $t;
type IntoIter = std::iter::Once<$t>;
fn into_iter(self) -> Self::IntoIter {
std::iter::once(self)
}
}
}
}
impl_into_iterator!(Packet);
impl_into_iterator!(Unknown);
impl_into_iterator!(Signature);
impl_into_iterator!(OnePassSig);
impl_into_iterator!(Marker);
impl_into_iterator!(Trust);
impl_into_iterator!(UserID);
impl_into_iterator!(UserAttribute);
impl_into_iterator!(Literal);
impl_into_iterator!(CompressedData);
impl_into_iterator!(PKESK);
impl_into_iterator!(SKESK);
impl_into_iterator!(SEIP);
impl_into_iterator!(MDC);
impl_into_iterator!(Key<P, R> where P: key::KeyParts, R: key::KeyRole);
impl From<Packet> for Result<Packet> {
fn from(p: Packet) -> Self {
Ok(p)
}
}
impl Packet {
pub fn tag(&self) -> Tag {
match self {
Packet::Unknown(ref packet) => packet.tag(),
Packet::Signature(_) => Tag::Signature,
Packet::OnePassSig(_) => Tag::OnePassSig,
Packet::PublicKey(_) => Tag::PublicKey,
Packet::PublicSubkey(_) => Tag::PublicSubkey,
Packet::SecretKey(_) => Tag::SecretKey,
Packet::SecretSubkey(_) => Tag::SecretSubkey,
Packet::Marker(_) => Tag::Marker,
Packet::Trust(_) => Tag::Trust,
Packet::UserID(_) => Tag::UserID,
Packet::UserAttribute(_) => Tag::UserAttribute,
Packet::Literal(_) => Tag::Literal,
Packet::CompressedData(_) => Tag::CompressedData,
Packet::PKESK(_) => Tag::PKESK,
Packet::SKESK(_) => Tag::SKESK,
Packet::SEIP(_) => Tag::SEIP,
#[allow(deprecated)]
Packet::MDC(_) => Tag::MDC,
Packet::Padding(_) => Tag::Padding,
}
}
pub fn kind(&self) -> Option<Tag> {
match self {
Packet::Unknown(_) => None,
_ => Some(self.tag()),
}
}
pub fn is_critical(&self) -> bool {
self.tag().is_critical()
}
pub fn version(&self) -> Option<u8> {
match self {
Packet::Unknown(_) => None,
Packet::Signature(p) => Some(p.version()),
Packet::OnePassSig(p) => Some(p.version()),
Packet::PublicKey(p) => Some(p.version()),
Packet::PublicSubkey(p) => Some(p.version()),
Packet::SecretKey(p) => Some(p.version()),
Packet::SecretSubkey(p) => Some(p.version()),
Packet::Marker(_) => None,
Packet::Trust(_) => None,
Packet::UserID(_) => None,
Packet::UserAttribute(_) => None,
Packet::Literal(_) => None,
Packet::CompressedData(_) => None,
Packet::PKESK(p) => Some(p.version()),
Packet::SKESK(p) => Some(p.version()),
Packet::SEIP(p) => Some(p.version()),
#[allow(deprecated)]
Packet::MDC(_) => None,
Packet::Padding(_) => None,
}
}
pub fn normalized_hash<H>(&self, state: &mut H)
where H: Hasher
{
use std::hash::Hash;
match self {
Packet::Signature(sig) => sig.normalized_hash(state),
Packet::OnePassSig(x) => Hash::hash(&x, state),
Packet::PublicKey(k) => k.public_hash(state),
Packet::PublicSubkey(k) => k.public_hash(state),
Packet::SecretKey(k) => k.public_hash(state),
Packet::SecretSubkey(k) => k.public_hash(state),
Packet::Marker(x) => Hash::hash(&x, state),
Packet::Trust(x) => Hash::hash(&x, state),
Packet::UserID(x) => Hash::hash(&x, state),
Packet::UserAttribute(x) => Hash::hash(&x, state),
Packet::Literal(x) => Hash::hash(&x, state),
Packet::CompressedData(x) => Hash::hash(&x, state),
Packet::PKESK(x) => Hash::hash(&x, state),
Packet::SKESK(x) => Hash::hash(&x, state),
Packet::SEIP(x) => Hash::hash(&x, state),
#[allow(deprecated)]
Packet::MDC(x) => Hash::hash(&x, state),
Packet::Unknown(x) => Hash::hash(&x, state),
Packet::Padding(x) => Padding::hash(x, state),
}
}
}
impl Packet {
fn common(&self) -> &Common {
match self {
Packet::Unknown(ref packet) => &packet.common,
Packet::Signature(ref packet) => &packet.common,
Packet::OnePassSig(OnePassSig::V3(packet)) => &packet.common,
Packet::OnePassSig(OnePassSig::V6(packet)) => &packet.common.common,
Packet::PublicKey(Key::V4(packet)) => &packet.common,
Packet::PublicKey(Key::V6(packet)) => &packet.common.common,
Packet::PublicSubkey(Key::V4(packet)) => &packet.common,
Packet::PublicSubkey(Key::V6(packet)) => &packet.common.common,
Packet::SecretKey(Key::V4(packet)) => &packet.common,
Packet::SecretKey(Key::V6(packet)) => &packet.common.common,
Packet::SecretSubkey(Key::V4(packet)) => &packet.common,
Packet::SecretSubkey(Key::V6(packet)) => &packet.common.common,
Packet::Marker(ref packet) => &packet.common,
Packet::Trust(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(PKESK::V3(packet)) => &packet.common,
Packet::PKESK(PKESK::V6(packet)) => &packet.common,
Packet::SKESK(SKESK::V4(ref packet)) => &packet.common,
Packet::SKESK(SKESK::V6(ref packet)) => &packet.skesk4.common,
Packet::SEIP(SEIP::V1(packet)) => &packet.common,
Packet::SEIP(SEIP::V2(packet)) => &packet.common,
#[allow(deprecated)]
Packet::MDC(ref packet) => &packet.common,
Packet::Padding(packet) => &packet.common,
}
}
}
impl fmt::Debug for Packet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fn debug_fmt(p: &Packet, f: &mut fmt::Formatter) -> fmt::Result {
match p {
Packet::Unknown(v) => write!(f, "Unknown({:?})", v),
Packet::Signature(v) => write!(f, "Signature({:?})", v),
Packet::OnePassSig(v) => write!(f, "OnePassSig({:?})", v),
Packet::PublicKey(v) => write!(f, "PublicKey({:?})", v),
Packet::PublicSubkey(v) => write!(f, "PublicSubkey({:?})", v),
Packet::SecretKey(v) => write!(f, "SecretKey({:?})", v),
Packet::SecretSubkey(v) => write!(f, "SecretSubkey({:?})", v),
Packet::Marker(v) => write!(f, "Marker({:?})", v),
Packet::Trust(v) => write!(f, "Trust({:?})", v),
Packet::UserID(v) => write!(f, "UserID({:?})", v),
Packet::UserAttribute(v) => write!(f, "UserAttribute({:?})", v),
Packet::Literal(v) => write!(f, "Literal({:?})", v),
Packet::CompressedData(v) => write!(f, "CompressedData({:?})", v),
Packet::PKESK(v) => write!(f, "PKESK({:?})", v),
Packet::SKESK(v) => write!(f, "SKESK({:?})", v),
Packet::SEIP(v) => write!(f, "SEIP({:?})", v),
#[allow(deprecated)]
Packet::MDC(v) => write!(f, "MDC({:?})", v),
Packet::Padding(v) => write!(f, "Padding({:?})", v),
}
}
fn try_armor_fmt(p: &Packet, f: &mut fmt::Formatter)
-> Result<fmt::Result> {
use crate::armor::{Writer, Kind};
use crate::serialize::Serialize;
let mut w = Writer::new(Vec::new(), Kind::File)?;
p.serialize(&mut w)?;
let buf = w.finalize()?;
Ok(f.write_str(std::str::from_utf8(&buf).expect("clean")))
}
if ! cfg!(test) {
debug_fmt(self, f)
} else {
try_armor_fmt(self, f).unwrap_or_else(|_| debug_fmt(self, f))
}
}
}
#[cfg(test)]
impl Arbitrary for Packet {
fn arbitrary(g: &mut Gen) -> Self {
use crate::arbitrary_helper::gen_arbitrary_from_range;
match gen_arbitrary_from_range(0..16, g) {
0 => Signature::arbitrary(g).into(),
1 => OnePassSig::arbitrary(g).into(),
2 => Key::<key::PublicParts, key::PrimaryRole>::arbitrary(g)
.into(),
3 => Key::<key::PublicParts, key::SubordinateRole>::arbitrary(g)
.into(),
4 => Key::<key::SecretParts, key::PrimaryRole>::arbitrary(g)
.into(),
5 => Key::<key::SecretParts, key::SubordinateRole>::arbitrary(g)
.into(),
6 => Marker::arbitrary(g).into(),
7 => Trust::arbitrary(g).into(),
8 => UserID::arbitrary(g).into(),
9 => UserAttribute::arbitrary(g).into(),
10 => Literal::arbitrary(g).into(),
11 => CompressedData::arbitrary(g).into(),
12 => PKESK::arbitrary(g).into(),
13 => SKESK::arbitrary(g).into(),
14 => Padding::arbitrary(g).into(),
15 => loop {
let mut u = Unknown::new(
Tag::arbitrary(g), anyhow::anyhow!("Arbitrary::arbitrary"));
u.set_body(Arbitrary::arbitrary(g));
let u = Packet::Unknown(u);
use crate::parse::Parse;
use crate::serialize::SerializeInto;
if let Ok(Packet::Unknown(_)) = Packet::from_bytes(
&u.to_vec().unwrap())
{
break u;
}
},
_ => unreachable!(),
}
}
}
#[derive(Default, Debug, Clone)]
pub(crate) struct Common {
dummy: std::marker::PhantomData<()>,
}
assert_send_and_sync!(Common);
impl Common {
pub(crate) const fn new() -> Self {
Common {
dummy: std::marker::PhantomData
}
}
}
#[cfg(test)]
impl Arbitrary for Common {
fn arbitrary(_: &mut Gen) -> Self {
Common::default()
}
}
impl PartialEq for Common {
fn eq(&self, _: &Common) -> bool {
true
}
}
impl Eq for Common {}
impl PartialOrd for Common {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Common {
fn cmp(&self, _: &Self) -> std::cmp::Ordering {
std::cmp::Ordering::Equal
}
}
impl std::hash::Hash for Common {
fn hash<H: std::hash::Hasher>(&self, _: &mut H) {
}
}
pub struct Iter<'a> {
children: slice::Iter<'a, Packet>,
child: Option<&'a Packet>,
grandchildren: Option<Box<Iter<'a>>>,
depth: usize,
}
assert_send_and_sync!(Iter<'_>);
impl<'a> Default for Iter<'a> {
fn default() -> Self {
Iter {
children: [].iter(),
child: None,
grandchildren: None,
depth: 0,
}
}
}
impl<'a> Iterator for Iter<'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 = child.descendants().map(Box::new);
}
self.depth = 0;
self.child
}
}
impl<'a> Iter<'a> {
pub fn paths(self)
-> impl Iterator<Item = (Vec<usize>, &'a Packet)> + Send + Sync
{
PacketPathIter {
iter: self,
path: None,
}
}
}
struct PacketPathIter<'a> {
iter: Iter<'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 crate::parse::Parse;
use crate::PacketPile;
fn paths<'a>(iter: impl Iterator<Item=&'a 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(container) = packet.container_ref() {
if let Some(c) = container.children() {
for mut path in paths(c).into_iter()
{
path.insert(0, i);
lpaths.push(path);
}
}
}
}
lpaths
}
for i in 1..5 {
let pile = PacketPile::from_bytes(
crate::tests::message(&format!("recursive-{}.pgp", 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.");
}
}
}
#[non_exhaustive]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
pub enum Signature {
V3(self::signature::Signature3),
V4(self::signature::Signature4),
V6(self::signature::Signature6),
}
assert_send_and_sync!(Signature);
impl Signature {
pub fn version(&self) -> u8 {
match self {
Signature::V3(_) => 3,
Signature::V4(_) => 4,
Signature::V6(_) => 6,
}
}
}
impl From<Signature> for Packet {
fn from(s: Signature) -> Self {
Packet::Signature(s)
}
}
impl Signature {
pub fn salt(&self) -> Option<&[u8]> {
match self {
Signature::V3(_) => None,
Signature::V4(_) => None,
Signature::V6(s) => Some(s.salt()),
}
}
}
impl Deref for Signature {
type Target = signature::Signature4;
fn deref(&self) -> &Self::Target {
match self {
Signature::V3(sig) => &sig.intern,
Signature::V4(sig) => sig,
Signature::V6(sig) => &sig.common,
}
}
}
impl DerefMut for Signature {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
Signature::V3(ref mut sig) => &mut sig.intern,
Signature::V4(ref mut sig) => sig,
Signature::V6(ref mut sig) => &mut sig.common,
}
}
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[non_exhaustive]
pub enum SEIP {
V1(self::seip::SEIP1),
V2(self::seip::SEIP2),
}
assert_send_and_sync!(SEIP);
impl SEIP {
pub fn version(&self) -> u8 {
match self {
SEIP::V1(_) => 1,
SEIP::V2(_) => 2,
}
}
}
impl From<SEIP> for Packet {
fn from(p: SEIP) -> Self {
Packet::SEIP(p)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::serialize::SerializeInto;
use crate::parse::Parse;
quickcheck! {
fn roundtrip(p: Packet) -> bool {
let buf = p.to_vec().expect("Failed to serialize packet");
let q = Packet::from_bytes(&buf).unwrap();
assert_eq!(p, q);
true
}
}
quickcheck! {
fn mutate_eq_discriminates(p: Packet, i: usize) -> bool {
if p.tag() == Tag::CompressedData {
return true;
}
let mut buf = p.to_vec().unwrap();
if buf.len() < 3 { return true; }
let bit = i % ((buf.len() - 2) * 8) + 16;
buf[bit / 8] ^= 1 << (bit % 8);
match Packet::from_bytes(&buf) {
Ok(q) => p != q,
Err(_) => true, }
}
}
#[test]
fn issue_802() -> Result<()> {
let pp = crate::PacketPile::from_bytes(b"-----BEGIN PGP ARMORED FILE-----
xiEE/////xIJKyQDAwIIAQENAFYp8M2JngCfc04tIwMBCuU=
-----END PGP ARMORED FILE-----
")?;
let p = pp.path_ref(&[0]).unwrap();
let buf = p.to_vec().expect("Failed to serialize packet");
let q = Packet::from_bytes(&buf).unwrap();
assert_eq!(p, &q);
Ok(())
}
}