pretty_good/
packet.rs

1use byteorder::{BigEndian, WriteBytesExt};
2use failure::Error;
3use nom::{ErrorKind, be_u16, be_u32, be_u8};
4use nom::Err as NomErr;
5use nom::IResult;
6
7use compression::*;
8use key::*;
9use literal::*;
10use marker;
11use signature::*;
12use types::NomError;
13use userid;
14
15named!(old_tag_format<(&[u8], usize), (u8, &[u8])>,
16    do_parse!(
17        tag: take_bits!(u8, 4) >>
18        length: switch!(take_bits!(u8, 2),
19            0 => bytes!(map!(be_u8, u32::from)) |
20            1 => bytes!(map!(be_u16, u32::from)) |
21            2 => bytes!(call!(be_u32)) |
22            _ => value!(0)
23        ) >>
24        data: bytes!(take!(length)) >>
25        ((tag, data))
26    )
27);
28
29fn new_tag_format(inp: (&[u8], usize)) -> IResult<(&[u8], usize), (u8, &[u8])> {
30    let (remaining, tag) = match take_bits!(inp, u8, 6) {
31        IResult::Done(remaining, tag) => (remaining, tag),
32        IResult::Error(e) => return IResult::Error(e),
33        IResult::Incomplete(i) => return IResult::Incomplete(i),
34    };
35
36    let (remaining, first_octet) = match bytes!(remaining, be_u8) {
37        IResult::Done(remaining, first_octet) => (remaining, first_octet),
38        IResult::Error(e) => return IResult::Error(e),
39        IResult::Incomplete(i) => return IResult::Incomplete(i),
40    };
41
42    if first_octet < 192 {
43        match bytes!(remaining, take!(first_octet)) {
44            IResult::Done(remaining, contents) => return IResult::Done(remaining, (tag, contents)),
45            IResult::Error(e) => return IResult::Error(e),
46            IResult::Incomplete(i) => return IResult::Incomplete(i),
47        }
48    } else if first_octet < 224 {
49        let (remaining, second_octet) = match bytes!(remaining, be_u8) {
50            IResult::Done(remaining, second_octet) => (remaining, second_octet),
51            IResult::Error(e) => return IResult::Error(e),
52            IResult::Incomplete(i) => return IResult::Incomplete(i),
53        };
54
55        let length = ((first_octet as u16 - 192) << 8) + second_octet as u16 + 192;
56
57        match bytes!(remaining, take!(length)) {
58            IResult::Done(remaining, contents) => return IResult::Done(remaining, (tag, contents)),
59            IResult::Error(e) => return IResult::Error(e),
60            IResult::Incomplete(i) => return IResult::Incomplete(i),
61        }
62    } else if first_octet == 255 {
63        let (remaining, length) = match bytes!(remaining, be_u32) {
64            IResult::Done(remaining, length) => (remaining, length),
65            IResult::Error(e) => return IResult::Error(e),
66            IResult::Incomplete(i) => return IResult::Incomplete(i),
67        };
68
69        match bytes!(remaining, take!(length)) {
70            IResult::Done(remaining, contents) => return IResult::Done(remaining, (tag, contents)),
71            IResult::Error(e) => return IResult::Error(e),
72            IResult::Incomplete(i) => return IResult::Incomplete(i),
73        }
74    }
75
76    // If we've gotten here, it's a partial-length packet, which we don't support (yet?).
77    IResult::Error(NomErr::Code(ErrorKind::Custom(
78        NomError::Unimplemented as u32,
79    )))
80}
81
82named!(
83    pgp_packet_header<(u8, &[u8])>,
84    bits!(preceded!(
85        tag_bits!(u8, 1, 0b1),
86        switch!(take_bits!(u8, 1),
87            0 => call!(old_tag_format) |
88            1 => call!(new_tag_format)
89        )
90    ))
91);
92
93/// An OpenPGP packet.
94///
95/// Each currently-implemented variant contains a single structure representing the contents of
96/// that packet type.
97#[derive(Clone, Debug)]
98pub enum Packet {
99    PublicKeySessionKey,
100    Signature(SignaturePacket),
101    SymmetricKeySessionKey,
102    OnePassSignature,
103    SecretKey(Key),
104    PublicKey(Key),
105    SecretSubkey(Key),
106    CompressedData(CompressedDataPacket),
107    SymmetricEncryptedData,
108    Marker,
109    LiteralData(LiteralPacket),
110    Trust,
111    UserId(String),
112    PublicSubkey(Key),
113    UserAttribute,
114    SymmetricEncryptedIntegrityProtectedData,
115    ModificationDetectionCode,
116}
117
118impl Packet {
119    fn packet_tag(&self) -> u8 {
120        match *self {
121            Packet::PublicKeySessionKey => 1,
122            Packet::Signature(_) => 2,
123            Packet::SymmetricKeySessionKey => 3,
124            Packet::OnePassSignature => 4,
125            Packet::SecretKey(_) => 5,
126            Packet::PublicKey(_) => 6,
127            Packet::SecretSubkey(_) => 7,
128            Packet::CompressedData(_) => 8,
129            Packet::SymmetricEncryptedData => 9,
130            Packet::Marker => 10,
131            Packet::LiteralData(_) => 11,
132            Packet::Trust => 12,
133            Packet::UserId(_) => 13,
134            Packet::PublicSubkey(_) => 14,
135            Packet::UserAttribute => 17,
136            Packet::SymmetricEncryptedIntegrityProtectedData => 18,
137            Packet::ModificationDetectionCode => 19,
138        }
139    }
140
141    pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
142        let mut out = Vec::new();
143
144        let body = match self {
145            &Packet::Signature(ref signature) => signature.to_bytes()?,
146            &Packet::SecretKey(ref key) => key.to_bytes()?,
147            &Packet::PublicKey(ref key) => key.to_bytes()?,
148            &Packet::SecretSubkey(ref key) => key.to_bytes()?,
149            &Packet::CompressedData(ref cdata) => cdata.to_bytes()?,
150            &Packet::Marker => Vec::from(marker::MARKER_PACKET),
151            &Packet::LiteralData(ref data) => data.to_bytes()?,
152            &Packet::UserId(ref id) => Vec::from(id.as_bytes()),
153            &Packet::PublicSubkey(ref key) => key.to_bytes()?,
154            p => bail!(PacketError::UnimplementedType { packet_type: format!("{:?}", p) }),
155        };
156
157        let mut packet_tag = 0b1000_0000;
158        let packet_type = self.packet_tag() << 2;
159        packet_tag |= packet_type;
160
161        if body.len() < ::std::u8::MAX as usize {
162            // Header is 2 octets long. packet_tag is unchanged.
163            out.push(packet_tag);
164            out.push(body.len() as u8);
165        } else if body.len() < ::std::u16::MAX as usize {
166            // Header is 3 octets long.
167            out.push(packet_tag | 0x1);
168            out.write_u16::<BigEndian>(body.len() as u16)?;
169        } else {
170            // Header is 5 octets long.
171            out.push(packet_tag | 0x2);
172            out.write_u32::<BigEndian>(body.len() as u32)?;
173        }
174
175        out.extend(&body);
176
177        Ok(out)
178    }
179
180    pub fn from_bytes(bytes: &[u8]) -> Result<(Packet, &[u8]), Error> {
181        let (remaining, packet_tag, packet_data) = match pgp_packet_header(bytes) {
182            IResult::Done(remaining, (tag, data)) => (remaining, tag, data),
183            IResult::Error(NomErr::Code(ErrorKind::Custom(e))) => {
184                let e = NomError::from(e);
185
186                bail!(PacketError::UnsupportedHeader {
187                    reason: format!("{:?}", e),
188                })
189            }
190            IResult::Error(e) => bail!(PacketError::InvalidHeader {
191                reason: format!("{}", e),
192            }),
193            IResult::Incomplete(i) => bail!(PacketError::InvalidHeader {
194                reason: format!("{:?}", i),
195            }),
196        };
197
198        let packet = match packet_tag {
199            0 => bail!(PacketError::InvalidHeader {
200                reason: format!("packet has reserved tag"),
201            }),
202            1 => Packet::PublicKeySessionKey,
203            2 => Packet::Signature(SignaturePacket::from_bytes(packet_data)?),
204            3 => Packet::SymmetricKeySessionKey,
205            4 => Packet::OnePassSignature,
206            5 => Packet::SecretKey(Key::from_bytes(packet_data)?),
207            6 => Packet::PublicKey(Key::from_bytes(packet_data)?),
208            7 => Packet::SecretSubkey(Key::from_bytes(packet_data)?),
209            8 => Packet::CompressedData(CompressedDataPacket::from_bytes(packet_data)?),
210            9 => Packet::SymmetricEncryptedData,
211            10 => {
212                marker::verify_marker(packet_data)?;
213                Packet::Marker
214            }
215            11 => Packet::LiteralData(LiteralPacket::from_bytes(packet_data)?),
216            12 => Packet::Trust,
217            13 => Packet::UserId(userid::parse_userid(packet_data)?),
218            14 => Packet::PublicSubkey(Key::from_bytes(packet_data)?),
219            17 => Packet::UserAttribute,
220            18 => Packet::SymmetricEncryptedIntegrityProtectedData,
221            19 => Packet::ModificationDetectionCode,
222            _ => bail!(PacketError::InvalidHeader {
223                reason: format!("unknown tag"),
224            }),
225        };
226
227        Ok((packet, remaining))
228    }
229
230    pub fn all_from_bytes(mut bytes: &[u8]) -> Result<Vec<Packet>, Error> {
231        let mut out = Vec::new();
232
233        while !bytes.is_empty() {
234            let (packet, remaining) = Packet::from_bytes(bytes)?;
235            out.push(packet);
236            bytes = remaining;
237        }
238
239        Ok(out)
240    }
241}
242
243/// Error type for [`Packet`]-level errors.
244///
245/// [`Packet`]: enum.Packet.html
246#[derive(Debug, Fail)]
247pub enum PacketError {
248    #[fail(display = "Invalid packet header: {}", reason)]
249    InvalidHeader { reason: String },
250    #[fail(display = "Unsupported packet header: {}", reason)]
251    UnsupportedHeader { reason: String },
252    #[fail(display = "Unimplemented packet type: {}", packet_type)]
253    UnimplementedType { packet_type: String },
254}