pretty_good/
signature.rs

1use std::cell::RefCell;
2use std::time::{Duration, SystemTime, UNIX_EPOCH};
3
4use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
5use failure::Error;
6use nom::{rest, be_u16, be_u32, be_u64, be_u8};
7use nom::{ErrorKind, IResult};
8use nom::Err as NomErr;
9use num::BigUint;
10
11use types::*;
12use util::parse_time_subpacket;
13
14#[cfg_attr(rustfmt, rustfmt_skip)]
15named!(
16    v3_sig<SignaturePacket>,
17    do_parse!(
18        tag!(b"\x03") >>
19        tag!(b"\x05") >>
20        signature_type: be_u8 >>
21        creation_time: be_u32 >>
22        signer: be_u64 >>
23        pubkey_algo: be_u8 >>
24        hash_algo: be_u8 >>
25        payload_hash: take!(2) >>
26        signature: call!(rest) >>
27        (SignaturePacket {
28            sig_type: SignatureType::from(signature_type),
29            timestamp: Some(Duration::from_secs(u64::from(creation_time))),
30            signer: Some(signer),
31            pubkey_algo: PublicKeyAlgorithm::from(pubkey_algo),
32            hash_algo: HashAlgorithm::from(hash_algo),
33            hashed_subpackets: Vec::new(),
34            unhashed_subpackets: Vec::new(),
35            signature_contents: Vec::from(signature),
36            payload_hash: RefCell::new(Some([payload_hash[0], payload_hash[1]])),
37        })
38    )
39);
40
41fn subpacket_length(inp: &[u8]) -> IResult<&[u8], u32> {
42    let (remaining, first_octet) = match be_u8(inp) {
43        IResult::Done(remaining, first_octet) => (remaining, first_octet),
44        IResult::Error(e) => return IResult::Error(e),
45        IResult::Incomplete(i) => return IResult::Incomplete(i),
46    };
47
48    if first_octet < 192 {
49        IResult::Done(remaining, u32::from(first_octet))
50    } else if first_octet < 255 {
51        let (remaining, second_octet) = match be_u8(remaining) {
52            IResult::Done(remaining, second_octet) => (remaining, second_octet),
53            IResult::Error(e) => return IResult::Error(e),
54            IResult::Incomplete(i) => return IResult::Incomplete(i),
55        };
56
57        let length = ((u16::from(first_octet) - 192) << 8) + u16::from(second_octet) + 192;
58
59        IResult::Done(remaining, u32::from(length))
60    } else {
61        be_u32(remaining)
62    }
63}
64
65fn parse_keyid_subpacket<T>(mut inp: &[u8]) -> Result<u64, NomErr<T>> {
66    inp.read_u64::<BigEndian>()
67        .map_err(|_| NomErr::Code(ErrorKind::Custom(NomError::IntegerReadError as u32)))
68}
69
70fn parse_hash_algorithms(inp: &[u8]) -> Vec<HashAlgorithm> {
71    inp.into_iter()
72        .map(|val| HashAlgorithm::from(*val))
73        .collect::<Vec<_>>()
74}
75
76fn parse_bool(inp: &[u8]) -> bool {
77    inp[0] != 0
78}
79
80fn parse_subpacket(inp: &[u8]) -> IResult<&[u8], Subpacket> {
81    let (remaining, length) = match subpacket_length(inp) {
82        IResult::Done(remaining, length) => (remaining, length),
83        IResult::Error(e) => return IResult::Error(e),
84        IResult::Incomplete(i) => return IResult::Incomplete(i),
85    };
86
87    let (remaining, subpacket_type) = match be_u8(remaining) {
88        IResult::Done(remaining, subpacket_type) => (remaining, subpacket_type),
89        IResult::Error(e) => return IResult::Error(e),
90        IResult::Incomplete(i) => return IResult::Incomplete(i),
91    };
92
93    let (remaining, packet_contents) = match take!(remaining, length - 1) {
94        IResult::Done(remaining, contents) => (remaining, contents),
95        IResult::Error(e) => return IResult::Error(e),
96        IResult::Incomplete(i) => return IResult::Incomplete(i),
97    };
98
99    match SubpacketType::from(subpacket_type) {
100        SubpacketType::Reserved => IResult::Error(NomErr::Code(ErrorKind::Custom(
101            NomError::UseOfReservedValue as u32,
102        ))),
103        SubpacketType::SignatureCreationTime => parse_time_subpacket(packet_contents)
104            .map(|time| IResult::Done(remaining, Subpacket::SignatureCreationTime(time)))
105            .unwrap_or_else(IResult::Error),
106        SubpacketType::SignatureExpirationTime => parse_time_subpacket(packet_contents)
107            .map(|time| IResult::Done(remaining, Subpacket::SignatureExpirationTime(time)))
108            .unwrap_or_else(IResult::Error),
109        SubpacketType::ExportableCertification => IResult::Done(
110            remaining,
111            Subpacket::ExportableCertification(parse_bool(packet_contents))
112        ),
113        SubpacketType::Revocable => IResult::Done(
114            remaining,
115            Subpacket::Revocable(parse_bool(packet_contents))
116        ),
117        SubpacketType::KeyExpirationTime => parse_time_subpacket(packet_contents)
118            .map(|time| IResult::Done(remaining, Subpacket::KeyExpirationTime(time)))
119            .unwrap_or_else(IResult::Error),
120        SubpacketType::Issuer => parse_keyid_subpacket(packet_contents)
121            .map(|key_id| IResult::Done(remaining, Subpacket::Issuer(key_id)))
122            .unwrap_or_else(IResult::Error),
123        SubpacketType::PreferredHashAlgorithms => IResult::Done(
124            remaining,
125            Subpacket::PreferredHashAlgorithms(parse_hash_algorithms(packet_contents)),
126        ),
127        SubpacketType::PrimaryUserId => IResult::Done(
128            remaining,
129            Subpacket::PrimaryUserId(parse_bool(packet_contents)),
130        ),
131        _ => IResult::Done(remaining, Subpacket::Unknown(subpacket_type, Vec::from(packet_contents))),
132    }
133}
134
135named!(subpackets<Vec<Subpacket>>, many0!(parse_subpacket));
136
137fn find_timestamp(subpackets: &[Subpacket]) -> Option<Duration> {
138    for subpacket in subpackets {
139        if let Subpacket::SignatureCreationTime(out) = *subpacket {
140            return Some(out);
141        }
142    }
143
144    None
145}
146
147fn find_signer(subpackets: &[Subpacket]) -> Option<u64> {
148    for subpacket in subpackets {
149        if let Subpacket::Issuer(out) = *subpacket {
150            return Some(out);
151        }
152    }
153
154    None
155}
156
157#[cfg_attr(rustfmt, rustfmt_skip)]
158named!(
159    v4_sig<SignaturePacket>,
160    do_parse!(
161        tag!(b"\x04") >>
162        signature_type: be_u8 >>
163        pubkey_algo: be_u8 >>
164        hash_algo: be_u8 >>
165        hashed_subs: length_value!(be_u16, subpackets) >>
166        unhashed_subs: length_value!(be_u16, subpackets) >>
167        payload_hash: take!(2) >>
168        signature: call!(rest) >>
169        (SignaturePacket {
170            sig_type: SignatureType::from(signature_type),
171            timestamp: find_timestamp(&hashed_subs).or_else(|| find_timestamp(&unhashed_subs)),
172            signer: find_signer(&hashed_subs).or_else(|| find_signer(&unhashed_subs)),
173            pubkey_algo: PublicKeyAlgorithm::from(pubkey_algo),
174            hash_algo: HashAlgorithm::from(hash_algo),
175            hashed_subpackets: hashed_subs,
176            unhashed_subpackets: unhashed_subs,
177            signature_contents: Vec::from(signature),
178            payload_hash: RefCell::new(Some([payload_hash[0], payload_hash[1]])),
179        })
180    )
181);
182
183named!(signature<SignaturePacket>, alt!(v3_sig | v4_sig));
184
185/// The contents of a PGP signature packet.
186#[derive(Clone, Debug)]
187pub struct SignaturePacket {
188    pub sig_type: SignatureType,
189    timestamp: Option<Duration>,
190    signer: Option<u64>,
191    pub pubkey_algo: PublicKeyAlgorithm,
192    pub hash_algo: HashAlgorithm,
193    pub hashed_subpackets: Vec<Subpacket>,
194    pub unhashed_subpackets: Vec<Subpacket>,
195    signature_contents: Vec<u8>,
196    payload_hash: RefCell<Option<[u8; 2]>>,
197}
198
199impl SignaturePacket {
200    /// Create a new signature with the given parameters. The new signature's creation time will be
201    /// set to the current system time, and the contents will be empty.
202    pub fn new(
203        sig_type: SignatureType,
204        pubkey_algo: PublicKeyAlgorithm,
205        hash_algo: HashAlgorithm,
206    ) -> Result<SignaturePacket, Error> {
207        let timestamp = SystemTime::now().duration_since(UNIX_EPOCH)?;
208
209        Ok(SignaturePacket {
210            sig_type: sig_type,
211            timestamp: Some(timestamp),
212            signer: None,
213            pubkey_algo: pubkey_algo,
214            hash_algo: hash_algo,
215            hashed_subpackets: Vec::new(),
216            unhashed_subpackets: Vec::new(),
217            signature_contents: Vec::new(),
218            payload_hash: RefCell::new(None),
219        })
220    }
221
222    /// Retrieve the contents of this signature. For RSA signatures, this is a single
223    /// multiprecision integer representing `m^d mod n`; for DSA signatures this is two
224    /// multiprecision integers representing `r` and `s`.
225    pub fn contents(&self) -> Result<Signature, Error> {
226        match self.pubkey_algo {
227            PublicKeyAlgorithm::Rsa
228            | PublicKeyAlgorithm::RsaEncryptOnly
229            | PublicKeyAlgorithm::RsaSignOnly => {
230                let (mut header_slice, mpi_slice) = self.signature_contents.split_at(2);
231                let header = header_slice.read_u16::<BigEndian>()?;
232                // GPG uses the header to indicate the number of bits in the MPI; we care about the
233                // number of bytes.
234                let header = (header as f64 / 8.0).ceil() as usize;
235
236                if mpi_slice.len() < header {
237                    bail!(SignatureError::MalformedMpi);
238                }
239                let (mpi_slice, _) = mpi_slice.split_at(header);
240
241                let mpi = BigUint::from_bytes_be(mpi_slice);
242                Ok(Signature::Rsa(mpi))
243            }
244            PublicKeyAlgorithm::Dsa => {
245                let (mut header_r_slice, remaining) = self.signature_contents.split_at(2);
246                let header_r = header_r_slice.read_u16::<BigEndian>()?;
247                // GPG uses the header to indicate the number of bits in the MPI; we care about the
248                // number of bytes.
249                let header_r = (header_r as f64 / 8.0).ceil() as usize;
250
251                if remaining.len() < header_r {
252                    bail!(SignatureError::MalformedMpi);
253                }
254
255                let (mpi_r_slice, remaining) = remaining.split_at(header_r);
256
257                let (mut header_s_slice, mpi_s_slice) = remaining.split_at(2);
258                let header_s = header_s_slice.read_u16::<BigEndian>()?;
259                let header_s = (header_s as f64 / 8.0).ceil() as usize;
260
261                if mpi_s_slice.len() < header_s {
262                    bail!(SignatureError::MalformedMpi);
263                }
264
265                let mpi_r = BigUint::from_bytes_be(mpi_r_slice);
266                let mpi_s = BigUint::from_bytes_be(mpi_s_slice);
267
268                Ok(Signature::Dsa(mpi_r, mpi_s))
269            }
270            _ => Ok(Signature::Unknown(self.signature_contents.clone())),
271        }
272    }
273
274    /// Set the contents of this signature.
275    pub fn set_contents(&mut self, sig: Signature) -> Result<(), Error> {
276        match sig {
277            Signature::Rsa(mpi) => {
278                let mut mpi_header = Vec::new();
279
280                mpi_header.write_u16::<BigEndian>(mpi.bits() as u16)?;
281                mpi_header.extend(&mpi.to_bytes_be());
282
283                self.signature_contents = mpi_header;
284            }
285            Signature::Dsa(r, s) => {
286                let mut mpis = Vec::new();
287
288                mpis.write_u16::<BigEndian>(r.bits() as u16)?;
289                mpis.extend(&r.to_bytes_be());
290
291                mpis.write_u16::<BigEndian>(s.bits() as u16)?;
292                mpis.extend(&s.to_bytes_be());
293
294                self.signature_contents = mpis;
295            }
296            Signature::Unknown(payload) => self.signature_contents = payload.clone(),
297        }
298
299        Ok(())
300    }
301
302    /// Retrive the creation time of this signature.
303    pub fn timestamp(&self) -> Option<Duration> {
304        find_timestamp(&self.hashed_subpackets)
305            .or_else(|| find_timestamp(&self.unhashed_subpackets))
306            .or(self.timestamp)
307    }
308
309    /// Set the creation time of this signature.
310    pub fn set_timestamp(&mut self, timestamp: Duration) {
311        self.hashed_subpackets.retain(|subpacket| {
312            if let Subpacket::SignatureCreationTime(_) = *subpacket {
313                false
314            } else {
315                true
316            }
317        });
318        self.unhashed_subpackets.retain(|subpacket| {
319            if let Subpacket::SignatureCreationTime(_) = *subpacket {
320                false
321            } else {
322                true
323            }
324        });
325
326        self.hashed_subpackets
327            .push(Subpacket::SignatureCreationTime(timestamp));
328        self.timestamp = Some(timestamp);
329    }
330
331    /// Retrieve the key ID of this signature's issuer.
332    pub fn signer(&self) -> Option<u64> {
333        find_signer(&self.hashed_subpackets)
334            .or_else(|| find_signer(&self.unhashed_subpackets))
335            .or(self.signer)
336    }
337
338    /// Set the key ID of this signature's issuer.
339    pub fn set_signer(&mut self, signer: u64) {
340        self.hashed_subpackets.retain(|subpacket| {
341            if let Subpacket::Issuer(_) = *subpacket {
342                false
343            } else {
344                true
345            }
346        });
347        self.unhashed_subpackets.retain(|subpacket| {
348            if let Subpacket::Issuer(_) = *subpacket {
349                false
350            } else {
351                true
352            }
353        });
354
355        self.unhashed_subpackets.push(Subpacket::Issuer(signer));
356        self.signer = Some(signer);
357    }
358
359    /// Retrieve the preferred hash algorithms of this signature.
360    pub fn preferred_hash_algorithms(&self) -> Option<Vec<HashAlgorithm>> {
361        for subpacket in &self.hashed_subpackets {
362            if let Subpacket::PreferredHashAlgorithms(ref algos) = *subpacket {
363                return Some(algos.clone());
364            }
365        }
366
367        for subpacket in &self.unhashed_subpackets {
368            if let Subpacket::PreferredHashAlgorithms(ref algos) = *subpacket {
369                return Some(algos.clone());
370            }
371        }
372
373        None
374    }
375
376    /// Set the preferred hash algorithms of this signature. If `hashed` is true, this subpacket
377    /// will be added as a hashed subpacket.
378    pub fn set_preferred_hash_algorithms<T: AsRef<[HashAlgorithm]>>(&mut self, algos: T, hashed: bool) {
379        self.hashed_subpackets.retain(|subpacket| {
380            if let Subpacket::PreferredHashAlgorithms(_) = *subpacket {
381                false
382            } else {
383                true
384            }
385        });
386        self.unhashed_subpackets.retain(|subpacket| {
387            if let Subpacket::PreferredHashAlgorithms(_) = *subpacket {
388                false
389            } else {
390                true
391            }
392        });
393
394        let algos = Subpacket::PreferredHashAlgorithms(Vec::from(algos.as_ref()));
395        if hashed {
396            self.hashed_subpackets.push(algos);
397        } else {
398            self.unhashed_subpackets.push(algos);
399        }
400    }
401
402    fn common_header(&self) -> Result<Vec<u8>, Error> {
403        let mut header = Vec::new();
404
405        // Signature version 4
406        header.push(4);
407        header.push(self.sig_type.into());
408        header.push(self.pubkey_algo.into());
409        header.push(self.hash_algo.into());
410
411        // Since we may be an old (v3) signature packet, but we only emit new (v4) signature
412        // packets, ensure that there is a hashed subpacket with the timestamp available, since a
413        // signature _must_ have a timestamp hashed subpacket. However, we do not want to save this
414        // new hashed subpacket in this signature's real list, so we forget about it after this
415        // function.
416        let mut hashed_subpackets = self.hashed_subpackets.clone();
417        match find_timestamp(&self.hashed_subpackets) {
418            Some(_) => {}
419            None => match self.timestamp {
420                Some(timestamp) => {
421                    hashed_subpackets.push(Subpacket::SignatureCreationTime(timestamp))
422                }
423                None => bail!(SignatureError::Unusable {
424                    reason: "no SignatureCreationTime".to_string(),
425                }),
426            },
427        }
428
429        let mut hashed_subpackets_bytes: Vec<u8> = Vec::new();
430        for packet in &hashed_subpackets {
431            let packet_bytes = packet.to_bytes()?;
432            hashed_subpackets_bytes.extend(&packet_bytes);
433        }
434        // The hashed subpackets are preceded by a two-octet big-endian value representing the
435        // total length of all hashed subpackets.
436        header.write_u16::<BigEndian>(hashed_subpackets_bytes.len() as u16)?;
437        header.extend(&hashed_subpackets_bytes);
438
439        Ok(header)
440    }
441
442    /// Build a payload suitable for signing.
443    ///
444    /// Note that this payload must be placed in an ASN.1 DigestInfo structure prior to signing,
445    /// which is outside the scope of this library.
446    pub fn signable_payload<T: AsRef<[u8]>>(&self, payload: T) -> Result<Vec<u8>, Error> {
447        let mut signing_payload = Vec::from(payload.as_ref());
448
449        let common_header = self.common_header()?;
450        signing_payload.extend(&common_header);
451
452        // From RFC4880, Section 5.2.4:
453        // V4 signatures also hash in a final trailer of six octets: the
454        // version of the Signature packet, i.e., 0x04; 0xFF; and a four-octet,
455        // big-endian number that is the length of the hashed data from the
456        // Signature packet (note that this number does not include these final
457        // six octets).
458        let mut suffix = Vec::new();
459        suffix.push(0x04);
460        suffix.push(0xFF);
461        suffix.write_u32::<BigEndian>(common_header.len() as u32)?;
462        signing_payload.extend(&suffix);
463
464        let hash = self.hash_algo.hash(signing_payload)?;
465        if hash.len() >= 2 {
466            self.payload_hash.replace(Some([hash[0], hash[1]]));
467        }
468
469        Ok(hash)
470    }
471
472    /// Retrieve the header for this signature, i.e. everything except the MPI contents of the
473    /// signature.
474    pub fn header(&self) -> Result<Vec<u8>, Error> {
475        let mut header = self.common_header()?;
476
477        let mut unhashed_subpackets_bytes: Vec<u8> = Vec::new();
478        for packet in &self.unhashed_subpackets {
479            let packet_bytes = packet.to_bytes()?;
480            unhashed_subpackets_bytes.extend(&packet_bytes);
481        }
482        // The unhashed subpackets are preceded by a two-octet big-endian value representing the
483        // total length of all unhashed subpackets.
484        header.write_u16::<BigEndian>(unhashed_subpackets_bytes.len() as u16)?;
485        header.extend(&unhashed_subpackets_bytes);
486
487        match *self.payload_hash.borrow() {
488            Some(hash) => {
489                header.push(hash[0]);
490                header.push(hash[1]);
491            }
492            None => {
493                header.push(0);
494                header.push(0);
495            }
496        }
497
498        Ok(header)
499    }
500
501    /// Serialize this signature to bytes.
502    pub fn to_bytes(&self) -> Result<Vec<u8>, Error> {
503        let mut out = self.header()?;
504        out.extend(&self.signature_contents);
505
506        Ok(out)
507    }
508
509    /// Read in a signature from some bytes.
510    pub fn from_bytes(bytes: &[u8]) -> Result<SignaturePacket, Error> {
511        match signature(bytes) {
512            IResult::Done(_, sig) => Ok(sig),
513            IResult::Error(NomErr::Code(ErrorKind::Custom(e))) => {
514                let e = NomError::from(e);
515
516                bail!(SignatureError::InvalidFormat {
517                    reason: format!("{:?}", e),
518                })
519            }
520            IResult::Error(e) => bail!(SignatureError::InvalidFormat {
521                reason: format!("{}", e),
522            }),
523            IResult::Incomplete(i) => bail!(SignatureError::InvalidFormat {
524                reason: format!("{:?}", i),
525            }),
526        }
527    }
528}
529
530/// The type of content a signature covers. See [RFC4880 &sect;5.2.1].
531///
532/// [RFC4880 &sect;5.2.1]: https://tools.ietf.org/html/rfc4880#section-5.2.1
533#[derive(Clone, Copy, Debug, PartialEq, Eq)]
534#[repr(u8)]
535pub enum SignatureType {
536    BinaryDocument = 0x00,
537    TextDocument = 0x01,
538    Standalone = 0x02,
539    GenericCertification = 0x10,
540    PersonaCertification = 0x11,
541    CasualCertification = 0x12,
542    PositiveCertification = 0x13,
543    SubkeyBinding = 0x18,
544    PrimaryKeyBinding = 0x19,
545    DirectKey = 0x1F,
546    KeyRevocation = 0x20,
547    SubkeyRevocation = 0x28,
548    CertificationRevocation = 0x30,
549    Timestamp = 0x40,
550    ThirdPartyConfirmation = 0x50,
551    Unknown = 255,
552}
553
554impl From<u8> for SignatureType {
555    fn from(val: u8) -> SignatureType {
556        match val {
557            0x00 => SignatureType::BinaryDocument,
558            0x01 => SignatureType::TextDocument,
559            0x02 => SignatureType::Standalone,
560            0x10 => SignatureType::GenericCertification,
561            0x11 => SignatureType::PersonaCertification,
562            0x12 => SignatureType::CasualCertification,
563            0x13 => SignatureType::PositiveCertification,
564            0x18 => SignatureType::SubkeyBinding,
565            0x19 => SignatureType::PrimaryKeyBinding,
566            0x1F => SignatureType::DirectKey,
567            0x20 => SignatureType::KeyRevocation,
568            0x28 => SignatureType::SubkeyRevocation,
569            0x30 => SignatureType::CertificationRevocation,
570            0x40 => SignatureType::Timestamp,
571            0x50 => SignatureType::ThirdPartyConfirmation,
572            _ => SignatureType::Unknown,
573        }
574    }
575}
576
577impl From<SignatureType> for u8 {
578    fn from(val: SignatureType) -> u8 {
579        match val {
580            SignatureType::BinaryDocument => 0x00,
581            SignatureType::TextDocument => 0x01,
582            SignatureType::Standalone => 0x02,
583            SignatureType::GenericCertification => 0x10,
584            SignatureType::PersonaCertification => 0x11,
585            SignatureType::CasualCertification => 0x12,
586            SignatureType::PositiveCertification => 0x13,
587            SignatureType::SubkeyBinding => 0x18,
588            SignatureType::PrimaryKeyBinding => 0x19,
589            SignatureType::DirectKey => 0x1F,
590            SignatureType::KeyRevocation => 0x20,
591            SignatureType::SubkeyRevocation => 0x28,
592            SignatureType::CertificationRevocation => 0x30,
593            SignatureType::Timestamp => 0x40,
594            SignatureType::ThirdPartyConfirmation => 0x50,
595            SignatureType::Unknown => 0xFF,
596        }
597    }
598}
599
600/// Type for [`SignaturePacket`] subpackets. See [RFC4880 &sect;5.2.3.1].
601///
602/// [`SignaturePacket`]: struct.SignaturePacket.html
603/// [RFC4880 &sect;5.2.3.1]: https://tools.ietf.org/html/rfc4880#section-5.2.3.1
604#[derive(Clone, Debug)]
605pub enum Subpacket {
606    SignatureCreationTime(Duration),
607    SignatureExpirationTime(Duration),
608    ExportableCertification(bool),
609    TrustSignature,
610    RegularExpression,
611    Revocable(bool),
612    KeyExpirationTime(Duration),
613    PreferredSymmetricAlgorithms,
614    RevocationKey,
615    Issuer(u64),
616    NotationData,
617    PreferredHashAlgorithms(Vec<HashAlgorithm>),
618    PreferredCompressionAlgorithms,
619    KeyServerPreferences,
620    PreferredKeyServer,
621    PrimaryUserId(bool),
622    PolicyUri,
623    KeyFlags,
624    SignerUserId,
625    RevocationReason,
626    Features,
627    SignatureTarget,
628    EmbeddedSignature,
629    Unknown(u8, Vec<u8>),
630}
631
632impl Subpacket {
633    fn to_bytes(&self) -> Result<Vec<u8>, Error> {
634        let mut out: Vec<u8> = Vec::new();
635
636        match *self {
637            Subpacket::SignatureCreationTime(time) => {
638                out.push(SubpacketType::SignatureCreationTime as u8);
639                out.write_u32::<BigEndian>(time.as_secs() as u32)?;
640            }
641            Subpacket::SignatureExpirationTime(time) => {
642                out.push(SubpacketType::SignatureExpirationTime as u8);
643                out.write_u32::<BigEndian>(time.as_secs() as u32)?;
644            }
645            Subpacket::ExportableCertification(exportable) => {
646                out.push(SubpacketType::ExportableCertification as u8);
647                out.push(exportable as u8);
648            }
649            Subpacket::Revocable(revocable) => {
650                out.push(SubpacketType::Revocable as u8);
651                out.push(revocable as u8);
652            }
653            Subpacket::KeyExpirationTime(time) => {
654                out.push(SubpacketType::KeyExpirationTime as u8);
655                out.write_u32::<BigEndian>(time.as_secs() as u32)?;
656            }
657            Subpacket::Issuer(issuer) => {
658                out.push(SubpacketType::Issuer as u8);
659                out.write_u64::<BigEndian>(issuer)?;
660            }
661            Subpacket::PreferredHashAlgorithms(ref algos) => {
662                out.push(SubpacketType::PreferredHashAlgorithms as u8);
663                for algo in algos {
664                    out.push(*algo as u8);
665                }
666            }
667            Subpacket::PrimaryUserId(primary) => {
668                out.push(SubpacketType::PrimaryUserId as u8);
669                out.push(primary as u8);
670            }
671            Subpacket::Unknown(tag, ref contents) => {
672                out.push(tag);
673                out.extend(contents);
674            }
675            _ => {}
676        }
677
678        let mut packet_len = if out.len() < 192 {
679            vec![out.len() as u8]
680        } else {
681            let mut packet_len = vec![255u8];
682            packet_len.write_u32::<BigEndian>(out.len() as u32)?;
683            packet_len
684        };
685
686        packet_len.extend(&out);
687        Ok(packet_len)
688    }
689}
690
691/// Actual multiprecision integer signature contents.
692///
693/// For RSA signatures, this is the multiprecision integer representing `m^d mod n`. For DSA
694/// signatures, this is two multiprecision integers representing `r` and `s`, respectively.
695#[derive(Clone, Debug, PartialEq, Eq)]
696pub enum Signature {
697    Rsa(BigUint),
698    Dsa(BigUint, BigUint),
699    Unknown(Vec<u8>),
700}
701
702/// Error type for [`SignaturePacket`]-level errors.
703///
704/// [`SignaturePacket`]: struct.SignaturePacket.html
705#[derive(Debug, Fail)]
706pub enum SignatureError {
707    #[fail(display = "Invalid signature format: {}", reason)]
708    InvalidFormat { reason: String },
709    #[fail(display = "Unusable signature: {}", reason)]
710    Unusable { reason: String },
711    #[fail(display = "Malformed MPI payload")]
712    MalformedMpi,
713}
714
715#[derive(Clone, Copy, Debug, PartialEq, Eq)]
716#[repr(u8)]
717enum SubpacketType {
718    SignatureCreationTime = 2,
719    SignatureExpirationTime = 3,
720    ExportableCertification = 4,
721    TrustSignature = 5,
722    RegularExpression = 6,
723    Revocable = 7,
724    KeyExpirationTime = 9,
725    PreferredSymmetricAlgorithms = 11,
726    RevocationKey = 12,
727    Issuer = 16,
728    NotationData = 20,
729    PreferredHashAlgorithms = 21,
730    PreferredCompressionAlgorithms = 22,
731    KeyServerPreferences = 23,
732    PreferredKeyServer = 24,
733    PrimaryUserId = 25,
734    PolicyUri = 26,
735    KeyFlags = 27,
736    SignerUserId = 28,
737    RevocationReason = 29,
738    Features = 30,
739    SignatureTarget = 31,
740    EmbeddedSignature = 32,
741    Reserved,
742    Unknown,
743}
744
745impl From<u8> for SubpacketType {
746    fn from(t: u8) -> SubpacketType {
747        match t {
748            0 | 1 | 8 | 13 | 14 | 15 | 17 | 18 | 19 => SubpacketType::Reserved,
749            2 => SubpacketType::SignatureCreationTime,
750            3 => SubpacketType::SignatureExpirationTime,
751            4 => SubpacketType::ExportableCertification,
752            5 => SubpacketType::TrustSignature,
753            6 => SubpacketType::RegularExpression,
754            7 => SubpacketType::Revocable,
755            9 => SubpacketType::KeyExpirationTime,
756            11 => SubpacketType::PreferredSymmetricAlgorithms,
757            12 => SubpacketType::RevocationKey,
758            16 => SubpacketType::Issuer,
759            20 => SubpacketType::NotationData,
760            21 => SubpacketType::PreferredHashAlgorithms,
761            22 => SubpacketType::PreferredCompressionAlgorithms,
762            23 => SubpacketType::KeyServerPreferences,
763            24 => SubpacketType::PreferredKeyServer,
764            25 => SubpacketType::PrimaryUserId,
765            26 => SubpacketType::PolicyUri,
766            27 => SubpacketType::KeyFlags,
767            28 => SubpacketType::SignerUserId,
768            29 => SubpacketType::RevocationReason,
769            30 => SubpacketType::Features,
770            31 => SubpacketType::SignatureTarget,
771            32 => SubpacketType::EmbeddedSignature,
772            _ => SubpacketType::Unknown,
773        }
774    }
775}