1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use std::io;

use crate::errors::Result;
use crate::packet::{
    CompressedData, LiteralData, Marker, ModDetectionCode, OnePassSignature, PublicKey,
    PublicKeyEncryptedSessionKey, PublicSubkey, SecretKey, SecretSubkey, Signature,
    SymEncryptedData, SymEncryptedProtectedData, SymKeyEncryptedSessionKey, Trust, UserAttribute,
    UserId,
};
use crate::ser::Serialize;
use crate::types::{Tag, Version};

#[derive(Debug)]
#[cfg_attr(feature = "cargo-clippy", allow(clippy::large_enum_variant))] // TODO: fix me
pub enum Packet {
    CompressedData(CompressedData),
    PublicKey(PublicKey),
    PublicSubkey(PublicSubkey),
    SecretKey(SecretKey),
    SecretSubkey(SecretSubkey),
    LiteralData(LiteralData),
    Marker(Marker),
    ModDetectionCode(ModDetectionCode),
    OnePassSignature(OnePassSignature),
    PublicKeyEncryptedSessionKey(PublicKeyEncryptedSessionKey),
    Signature(Signature),
    SymEncryptedData(SymEncryptedData),
    SymEncryptedProtectedData(SymEncryptedProtectedData),
    SymKeyEncryptedSessionKey(SymKeyEncryptedSessionKey),
    Trust(Trust),
    UserAttribute(UserAttribute),
    UserId(UserId),
}

impl Packet {
    /// Returns the tag for this packet type.
    pub fn tag(&self) -> Tag {
        match self {
            Packet::CompressedData(_) => Tag::CompressedData,
            Packet::PublicKey(_) => Tag::PublicKey,
            Packet::PublicSubkey(_) => Tag::PublicSubkey,
            Packet::SecretKey(_) => Tag::SecretKey,
            Packet::SecretSubkey(_) => Tag::SecretSubkey,
            Packet::LiteralData(_) => Tag::LiteralData,
            Packet::Marker(_) => Tag::Marker,
            Packet::ModDetectionCode(_) => Tag::ModDetectionCode,
            Packet::OnePassSignature(_) => Tag::OnePassSignature,
            Packet::PublicKeyEncryptedSessionKey(_) => Tag::PublicKeyEncryptedSessionKey,
            Packet::Signature(_) => Tag::Signature,
            Packet::SymEncryptedData(_) => Tag::SymEncryptedData,
            Packet::SymEncryptedProtectedData(_) => Tag::SymEncryptedProtectedData,
            Packet::SymKeyEncryptedSessionKey(_) => Tag::SymKeyEncryptedSessionKey,
            Packet::Trust(_) => Tag::Trust,
            Packet::UserAttribute(_) => Tag::UserAttribute,
            Packet::UserId(_) => Tag::UserId,
        }
    }

    pub fn packet_version(&self) -> Version {
        match self {
            Packet::CompressedData(p) => p.packet_version(),
            Packet::PublicKey(p) => p.packet_version(),
            Packet::PublicSubkey(p) => p.packet_version(),
            Packet::SecretKey(p) => p.packet_version(),
            Packet::SecretSubkey(p) => p.packet_version(),
            Packet::LiteralData(p) => p.packet_version(),
            Packet::Marker(p) => p.packet_version(),
            Packet::ModDetectionCode(p) => p.packet_version(),
            Packet::OnePassSignature(p) => p.packet_version(),
            Packet::PublicKeyEncryptedSessionKey(p) => p.packet_version(),
            Packet::Signature(p) => p.packet_version(),
            Packet::SymEncryptedData(p) => p.packet_version(),
            Packet::SymEncryptedProtectedData(p) => p.packet_version(),
            Packet::SymKeyEncryptedSessionKey(p) => p.packet_version(),
            Packet::Trust(p) => p.packet_version(),
            Packet::UserAttribute(p) => p.packet_version(),
            Packet::UserId(p) => p.packet_version(),
        }
    }
}

impl_try_from_into!(
    Packet,
    CompressedData => CompressedData,
    PublicKey => PublicKey,
    PublicSubkey => PublicSubkey,
    SecretKey => SecretKey,
    SecretSubkey => SecretSubkey,
    LiteralData => LiteralData,
    Marker => Marker,
    ModDetectionCode => ModDetectionCode,
    OnePassSignature => OnePassSignature,
    PublicKeyEncryptedSessionKey => PublicKeyEncryptedSessionKey,
    Signature => Signature,
    SymEncryptedData => SymEncryptedData,
    SymEncryptedProtectedData => SymEncryptedProtectedData,
    SymKeyEncryptedSessionKey => SymKeyEncryptedSessionKey,
    Trust => Trust,
    UserAttribute => UserAttribute,
    UserId => UserId
);

// TODO: move to its own file
impl Serialize for Packet {
    fn to_writer<W: io::Write>(&self, writer: &mut W) -> Result<()> {
        match self {
            Packet::CompressedData(p) => write_packet(writer, &p),
            Packet::PublicKey(p) => write_packet(writer, &p),
            Packet::PublicSubkey(p) => write_packet(writer, &p),
            Packet::SecretKey(p) => write_packet(writer, &p),
            Packet::SecretSubkey(p) => write_packet(writer, &p),
            Packet::LiteralData(p) => write_packet(writer, &p),
            Packet::Marker(p) => write_packet(writer, &p),
            Packet::ModDetectionCode(p) => write_packet(writer, &p),
            Packet::OnePassSignature(p) => write_packet(writer, &p),
            Packet::PublicKeyEncryptedSessionKey(p) => write_packet(writer, &p),
            Packet::Signature(p) => write_packet(writer, &p),
            Packet::SymEncryptedData(p) => write_packet(writer, &p),
            Packet::SymEncryptedProtectedData(p) => write_packet(writer, &p),
            Packet::SymKeyEncryptedSessionKey(p) => write_packet(writer, &p),
            Packet::Trust(p) => write_packet(writer, &p),
            Packet::UserAttribute(p) => write_packet(writer, &p),
            Packet::UserId(p) => write_packet(writer, &p),
        }
    }
}

pub trait PacketTrait: Serialize {
    fn packet_version(&self) -> Version;
    fn tag(&self) -> Tag;
}

impl<'a, T: 'a + PacketTrait> PacketTrait for &'a T {
    fn packet_version(&self) -> Version {
        (*self).packet_version()
    }

    fn tag(&self) -> Tag {
        (*self).tag()
    }
}

pub fn write_packet(writer: &mut impl io::Write, packet: &impl PacketTrait) -> Result<()> {
    let packet_version = packet.packet_version();
    let mut buf = Vec::new();
    packet.to_writer(&mut buf)?;
    debug!(
        "write_packet {:?} {:?} (len: {})",
        &packet_version,
        packet.tag(),
        buf.len()
    );

    // header
    packet_version.write_header(writer, packet.tag() as u8, buf.len())?;

    // the actual packet body
    writer.write_all(&buf)?;

    Ok(())
}