cmail_rpgp/packet/signature/
types.rs

1use std::io::Read;
2
3use bitfield::bitfield;
4use bstr::{BStr, BString};
5use byteorder::{BigEndian, ByteOrder};
6use chrono::{DateTime, Duration, Utc};
7use iter_read::IterRead;
8use log::debug;
9use num_enum::{FromPrimitive, IntoPrimitive};
10use smallvec::{smallvec, SmallVec};
11
12use crate::crypto::aead::AeadAlgorithm;
13use crate::crypto::hash::HashAlgorithm;
14use crate::crypto::public_key::PublicKeyAlgorithm;
15use crate::crypto::sym::SymmetricKeyAlgorithm;
16use crate::errors::Result;
17use crate::line_writer::LineBreak;
18use crate::normalize_lines::Normalized;
19use crate::packet::signature::SignatureConfig;
20use crate::packet::{PacketTrait, SignatureVersionSpecific};
21use crate::ser::Serialize;
22use crate::types::{
23    self, CompressionAlgorithm, Fingerprint, KeyId, KeyVersion, PublicKeyTrait, SignatureBytes,
24    Tag, Version,
25};
26
27/// Signature Packet
28/// <https://www.rfc-editor.org/rfc/rfc9580.html#name-signature-packet-type-id-2>
29#[derive(Clone, PartialEq, Eq, derive_more::Debug)]
30pub struct Signature {
31    packet_version: Version,
32
33    pub config: SignatureConfig,
34    #[debug("{}", hex::encode(signed_hash_value))]
35    pub signed_hash_value: [u8; 2],
36    pub signature: SignatureBytes,
37}
38
39impl Signature {
40    /// Constructor for an OpenPGP v2 signature packet.
41    /// Note: This is a historical packet version!
42    #[allow(clippy::too_many_arguments)]
43    pub fn v2(
44        packet_version: Version,
45        typ: SignatureType,
46        pub_alg: PublicKeyAlgorithm,
47        hash_alg: HashAlgorithm,
48        created: DateTime<Utc>,
49        issuer: KeyId,
50        signed_hash_value: [u8; 2],
51        signature: SignatureBytes,
52    ) -> Self {
53        Signature {
54            packet_version,
55            config: SignatureConfig {
56                typ,
57                pub_alg,
58                hash_alg,
59                hashed_subpackets: vec![],
60                unhashed_subpackets: vec![],
61                version_specific: SignatureVersionSpecific::V2 { created, issuer },
62            },
63            signed_hash_value,
64            signature,
65        }
66    }
67
68    /// Constructor for an OpenPGP v3 signature packet.
69    /// Note: This is a historical packet version!
70    #[allow(clippy::too_many_arguments)]
71    pub fn v3(
72        packet_version: Version,
73        typ: SignatureType,
74        pub_alg: PublicKeyAlgorithm,
75        hash_alg: HashAlgorithm,
76        created: DateTime<Utc>,
77        issuer: KeyId,
78        signed_hash_value: [u8; 2],
79        signature: SignatureBytes,
80    ) -> Self {
81        Signature {
82            packet_version,
83            config: SignatureConfig {
84                typ,
85                pub_alg,
86                hash_alg,
87                hashed_subpackets: vec![],
88                unhashed_subpackets: vec![],
89                version_specific: SignatureVersionSpecific::V3 { created, issuer },
90            },
91            signed_hash_value,
92            signature,
93        }
94    }
95
96    /// Constructor for an OpenPGP v4 signature packet.
97    ///
98    /// OpenPGP v4 signatures are typically used with OpenPGP v4 keys, as specified in RFC 9580
99    /// (and formerly in 4880 and 2440).
100    #[allow(clippy::too_many_arguments)]
101    pub fn v4(
102        packet_version: Version,
103        typ: SignatureType,
104        pub_alg: PublicKeyAlgorithm,
105        hash_alg: HashAlgorithm,
106        signed_hash_value: [u8; 2],
107        signature: SignatureBytes,
108        hashed_subpackets: Vec<Subpacket>,
109        unhashed_subpackets: Vec<Subpacket>,
110    ) -> Self {
111        Signature {
112            packet_version,
113            config: SignatureConfig {
114                typ,
115                pub_alg,
116                hash_alg,
117                hashed_subpackets,
118                unhashed_subpackets,
119                version_specific: SignatureVersionSpecific::V4,
120            },
121            signed_hash_value,
122            signature,
123        }
124    }
125
126    /// Constructor for an OpenPGP v6 signature packet.
127    ///
128    /// OpenPGP v6 signatures are specified in RFC 9580 and only used with OpenPGP v6 keys.
129    #[allow(clippy::too_many_arguments)]
130    pub fn v6(
131        packet_version: Version,
132        typ: SignatureType,
133        pub_alg: PublicKeyAlgorithm,
134        hash_alg: HashAlgorithm,
135        signed_hash_value: [u8; 2],
136        signature: SignatureBytes,
137        hashed_subpackets: Vec<Subpacket>,
138        unhashed_subpackets: Vec<Subpacket>,
139        salt: Vec<u8>,
140    ) -> Self {
141        Signature {
142            packet_version,
143            config: SignatureConfig {
144                typ,
145                pub_alg,
146                hash_alg,
147                hashed_subpackets,
148                unhashed_subpackets,
149                version_specific: SignatureVersionSpecific::V6 { salt },
150            },
151            signed_hash_value,
152            signature,
153        }
154    }
155
156    pub fn from_config(
157        config: SignatureConfig,
158        signed_hash_value: [u8; 2],
159        signature: SignatureBytes,
160    ) -> Self {
161        Signature {
162            packet_version: Default::default(),
163            config,
164            signed_hash_value,
165            signature,
166        }
167    }
168
169    /// Returns what kind of signature this is.
170    pub fn typ(&self) -> SignatureType {
171        self.config.typ()
172    }
173
174    /// The used `HashAlgorithm`.
175    pub fn hash_alg(&self) -> HashAlgorithm {
176        self.config.hash_alg
177    }
178
179    /// Does `key` match any issuer or issuer_fingerprint subpacket in `sig`?
180    /// If yes, we consider `key` a candidate to verify `sig` against.
181    ///
182    /// We also consider `key` a match for `sig` by default, if `sig` contains no issuer-related
183    /// subpackets.
184    fn match_identity(sig: &Signature, key: &impl PublicKeyTrait) -> bool {
185        let issuers = sig.issuer();
186        let issuer_fps = sig.issuer_fingerprint();
187
188        // If there is no subpacket that signals the issuer, we consider `sig` and `key` a
189        // potential match, and will check the cryptographic validity.
190        if issuers.is_empty() && issuer_fps.is_empty() {
191            return true;
192        }
193
194        // Does any issuer or issuer fingerprint subpacket matche the identity of `sig`?
195        issuers.iter().any(|&key_id| key_id == &key.key_id())
196            || issuer_fps.iter().any(|&fp| fp == &key.fingerprint())
197    }
198
199    /// Check alignment between signing key version and signature version.
200    ///
201    /// Version 6 signatures and version 6 keys are strongly linked:
202    /// - only a v6 key may produce a v6 signature
203    /// - a v6 key may only produce v6 signatures
204    fn check_signature_key_version_alignment(
205        key: &impl PublicKeyTrait,
206        config: &SignatureConfig,
207    ) -> Result<()> {
208        // Every signature made by a version 6 key MUST be a version 6 signature.
209        if key.version() == KeyVersion::V6 {
210            ensure_eq!(
211                config.version(),
212                SignatureVersion::V6,
213                "Non v6 signature by a v6 key is not allowed"
214            );
215        }
216
217        if config.version() == SignatureVersion::V6 {
218            ensure_eq!(
219                key.version(),
220                KeyVersion::V6,
221                "v6 signature by a non-v6 key is not allowed"
222            );
223        }
224
225        Ok(())
226    }
227
228    /// Verify this signature.
229    pub fn verify<R>(&self, key: &impl PublicKeyTrait, data: R) -> Result<()>
230    where
231        R: Read,
232    {
233        Self::check_signature_key_version_alignment(&key, &self.config)?;
234
235        ensure!(
236            Self::match_identity(self, key),
237            "verify: No matching issuer or issuer_fingerprint for Key ID: {:?}",
238            &key.key_id(),
239        );
240
241        let mut hasher = self.config.hash_alg.new_hasher()?;
242
243        if let SignatureVersionSpecific::V6 { salt } = &self.config.version_specific {
244            // Salt size must match the expected length for the hash algorithm that is used
245            //
246            // See: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3-2.10.2.1.1
247            ensure_eq!(
248                self.config.hash_alg.salt_len(),
249                Some(salt.len()),
250                "Illegal salt length {} for a V6 Signature using {:?}",
251                salt.len(),
252                self.config.hash_alg
253            );
254
255            hasher.update(salt.as_ref())
256        }
257
258        if matches!(self.typ(), SignatureType::Text) {
259            let normalized = Normalized::new(data.bytes().flat_map(|b| b.ok()), LineBreak::Crlf);
260
261            self.config
262                .hash_data_to_sign(&mut *hasher, IterRead::new(normalized))?;
263        } else {
264            self.config.hash_data_to_sign(&mut *hasher, data)?;
265        }
266        let len = self.config.hash_signature_data(&mut hasher)?;
267        hasher.update(&self.config.trailer(len)?);
268
269        let hash = &hasher.finish()[..];
270
271        // Check that the high 16 bits of the hash from the signature packet match with the hash we
272        // just calculated.
273        //
274        // "When verifying a version 6 signature, an implementation MUST reject the signature if
275        // these octets do not match the first two octets of the computed hash."
276        //
277        // (See https://www.rfc-editor.org/rfc/rfc9580.html#name-notes-on-signatures)
278        //
279        // (Note: we currently also reject v4 signatures if the calculated hash doesn't match the
280        // high 16 bits in the signature packet, even though RFC 9580 doesn't strictly require this)
281        ensure_eq!(
282            &self.signed_hash_value,
283            &hash[0..2],
284            "signature: invalid signed hash value"
285        );
286
287        key.verify_signature(self.config.hash_alg, hash, &self.signature)
288    }
289
290    /// Verifies a certification signature type (for self-signatures).
291    pub fn verify_certification(
292        &self,
293        key: &impl PublicKeyTrait,
294        tag: Tag,
295        id: &impl Serialize,
296    ) -> Result<()> {
297        self.verify_third_party_certification(&key, &key, tag, id)
298    }
299
300    /// Verifies a certification signature type (for third-party signatures).
301    pub fn verify_third_party_certification(
302        &self,
303        signee: &impl PublicKeyTrait,
304        signer: &impl PublicKeyTrait,
305        tag: Tag,
306        id: &impl Serialize,
307    ) -> Result<()> {
308        let key_id = signee.key_id();
309        debug!("verifying certification {:?} {:#?}", key_id, self);
310
311        Self::check_signature_key_version_alignment(&signer, &self.config)?;
312
313        ensure!(
314            Self::match_identity(self, signer),
315            "verify_certification: No matching issuer or issuer_fingerprint for Key ID: {:?}",
316            key_id,
317        );
318
319        let mut hasher = self.config.hash_alg.new_hasher()?;
320
321        if let SignatureVersionSpecific::V6 { salt } = &self.config.version_specific {
322            hasher.update(salt.as_ref())
323        }
324
325        // the key of the signee
326        {
327            let mut key_buf = Vec::new();
328            // TODO: this is different for V5
329            signee.serialize_for_hashing(&mut key_buf)?;
330            hasher.update(&key_buf);
331        }
332
333        // the packet content
334        {
335            let mut packet_buf = Vec::new();
336            id.to_writer(&mut packet_buf)?;
337
338            match self.config.version() {
339                SignatureVersion::V2 | SignatureVersion::V3 => {
340                    // Nothing to do
341                }
342                SignatureVersion::V4 | SignatureVersion::V6 => {
343                    let prefix = match tag {
344                        Tag::UserId => 0xB4,
345                        Tag::UserAttribute => 0xD1,
346                        _ => bail!("invalid tag for certification validation: {:?}", tag),
347                    };
348
349                    let mut prefix_buf = [prefix, 0u8, 0u8, 0u8, 0u8];
350                    BigEndian::write_u32(&mut prefix_buf[1..], packet_buf.len().try_into()?);
351
352                    // prefixes
353                    hasher.update(&prefix_buf);
354                }
355                SignatureVersion::V5 => {
356                    bail!("v5 signature unsupported tpc")
357                }
358                SignatureVersion::Other(version) => {
359                    bail!("unsupported signature version: {:?}", version)
360                }
361            }
362
363            hasher.update(&packet_buf);
364        }
365
366        let len = self.config.hash_signature_data(&mut hasher)?;
367        hasher.update(&self.config.trailer(len)?);
368
369        let hash = &hasher.finish()[..];
370        ensure_eq!(
371            &self.signed_hash_value,
372            &hash[0..2],
373            "certification: invalid signed hash value"
374        );
375
376        signer.verify_signature(self.config.hash_alg, hash, &self.signature)
377    }
378
379    /// Verifies a key binding (which binds a subkey to the primary key).
380    ///
381    /// "Subkey Binding Signature (type ID 0x18)"
382    pub fn verify_key_binding(
383        &self,
384        signing_key: &impl PublicKeyTrait,
385        key: &impl PublicKeyTrait,
386    ) -> Result<()> {
387        self.verify_key_binding_internal(signing_key, key, false)
388    }
389
390    /// Verifies a primary key binding signature, or "back signature" (which links the primary to a signing subkey).
391    ///
392    /// "Primary Key Binding Signature (type ID 0x19)"
393    pub fn verify_backwards_key_binding(
394        &self,
395        signing_key: &impl PublicKeyTrait,
396        key: &impl PublicKeyTrait,
397    ) -> Result<()> {
398        self.verify_key_binding_internal(signing_key, key, true)
399    }
400
401    /// Verify subkey binding signatures, either regular subkey binding, or a "back signature".
402    ///
403    /// - when backsig is false: verify a "Subkey Binding Signature (type ID 0x18)"
404    /// - when backsig is true: verify a "Primary Key Binding Signature (type ID 0x19)"
405    fn verify_key_binding_internal(
406        &self,
407        signer: &impl PublicKeyTrait,
408        signee: &impl PublicKeyTrait,
409        backsig: bool,
410    ) -> Result<()> {
411        debug!(
412            "verifying key binding: {:#?} - {:#?} - {:#?} (backsig: {})",
413            self, signer, signee, backsig
414        );
415
416        Self::check_signature_key_version_alignment(&signer, &self.config)?;
417
418        let mut hasher = self.config.hash_alg.new_hasher()?;
419
420        if let SignatureVersionSpecific::V6 { salt } = &self.config.version_specific {
421            hasher.update(salt.as_ref())
422        }
423
424        // Hash the two keys:
425        // - for a regular binding signature, first the signer (primary), then the signee (subkey)
426        // - for a "backward signature" (Primary Key Binding Signature), the order of hashing is signee (primary), signer (subkey)
427
428        // First key to hash
429        {
430            let mut key_buf = Vec::new();
431            if !backsig {
432                signer.serialize_for_hashing(&mut key_buf)?; // primary
433            } else {
434                signee.serialize_for_hashing(&mut key_buf)?; // primary
435            }
436
437            hasher.update(&key_buf);
438        }
439        // Second key to hash
440        {
441            let mut key_buf = Vec::new();
442            if !backsig {
443                signee.serialize_for_hashing(&mut key_buf)?; // subkey
444            } else {
445                signer.serialize_for_hashing(&mut key_buf)?; // subkey
446            }
447
448            hasher.update(&key_buf);
449        }
450
451        let len = self.config.hash_signature_data(&mut hasher)?;
452        hasher.update(&self.config.trailer(len)?);
453
454        let hash = &hasher.finish()[..];
455        ensure_eq!(
456            &self.signed_hash_value,
457            &hash[0..2],
458            "key binding: invalid signed hash value"
459        );
460
461        signer.verify_signature(self.config.hash_alg, hash, &self.signature)
462    }
463
464    /// Verifies a direct key signature or a revocation.
465    pub fn verify_key(&self, key: &impl PublicKeyTrait) -> Result<()> {
466        debug!("verifying key (revocation): {:#?} - {:#?}", self, key);
467
468        Self::check_signature_key_version_alignment(&key, &self.config)?;
469
470        ensure!(
471            Self::match_identity(self, key),
472            "verify_key: No matching issuer or issuer_fingerprint for Key ID: {:?}",
473            &key.key_id(),
474        );
475
476        let mut hasher = self.config.hash_alg.new_hasher()?;
477
478        if let SignatureVersionSpecific::V6 { salt } = &self.config.version_specific {
479            hasher.update(salt.as_ref())
480        }
481
482        {
483            let mut key_buf = Vec::new();
484            key.serialize_for_hashing(&mut key_buf)?;
485
486            hasher.update(&key_buf);
487        }
488
489        let len = self.config.hash_signature_data(&mut hasher)?;
490        hasher.update(&self.config.trailer(len)?);
491
492        let hash = &hasher.finish()[..];
493        ensure_eq!(
494            &self.signed_hash_value,
495            &hash[0..2],
496            "key: invalid signed hash value"
497        );
498
499        key.verify_signature(self.config.hash_alg, hash, &self.signature)
500    }
501
502    /// Returns if the signature is a certification or not.
503    pub fn is_certification(&self) -> bool {
504        self.config.is_certification()
505    }
506
507    pub fn key_expiration_time(&self) -> Option<&Duration> {
508        self.config.hashed_subpackets().find_map(|p| match &p.data {
509            SubpacketData::KeyExpirationTime(d) => Some(d),
510            _ => None,
511        })
512    }
513
514    pub fn signature_expiration_time(&self) -> Option<&Duration> {
515        self.config.hashed_subpackets().find_map(|p| match &p.data {
516            SubpacketData::SignatureExpirationTime(d) => Some(d),
517            _ => None,
518        })
519    }
520
521    pub fn created(&self) -> Option<&DateTime<Utc>> {
522        self.config.created()
523    }
524
525    pub fn issuer(&self) -> Vec<&KeyId> {
526        self.config.issuer()
527    }
528
529    pub fn issuer_fingerprint(&self) -> Vec<&Fingerprint> {
530        self.config.issuer_fingerprint()
531    }
532
533    pub fn preferred_symmetric_algs(&self) -> &[SymmetricKeyAlgorithm] {
534        self.config
535            .hashed_subpackets()
536            .find_map(|p| match &p.data {
537                SubpacketData::PreferredSymmetricAlgorithms(d) => Some(&d[..]),
538                _ => None,
539            })
540            .unwrap_or_else(|| &[][..])
541    }
542
543    pub fn preferred_aead_algs(&self) -> &[(SymmetricKeyAlgorithm, AeadAlgorithm)] {
544        self.config
545            .hashed_subpackets()
546            .find_map(|p| match &p.data {
547                SubpacketData::PreferredAeadAlgorithms(d) => Some(&d[..]),
548                _ => None,
549            })
550            .unwrap_or_else(|| &[][..])
551    }
552
553    pub fn preferred_hash_algs(&self) -> &[HashAlgorithm] {
554        self.config
555            .hashed_subpackets()
556            .find_map(|p| match &p.data {
557                SubpacketData::PreferredHashAlgorithms(d) => Some(&d[..]),
558                _ => None,
559            })
560            .unwrap_or_else(|| &[][..])
561    }
562
563    pub fn preferred_compression_algs(&self) -> &[CompressionAlgorithm] {
564        self.config
565            .hashed_subpackets()
566            .find_map(|p| match &p.data {
567                SubpacketData::PreferredCompressionAlgorithms(d) => Some(&d[..]),
568                _ => None,
569            })
570            .unwrap_or_else(|| &[][..])
571    }
572
573    pub fn key_server_prefs(&self) -> &[u8] {
574        self.config
575            .hashed_subpackets()
576            .find_map(|p| match &p.data {
577                SubpacketData::KeyServerPreferences(d) => Some(&d[..]),
578                _ => None,
579            })
580            .unwrap_or_else(|| &[][..])
581    }
582
583    pub fn key_flags(&self) -> KeyFlags {
584        self.config
585            .hashed_subpackets()
586            .find_map(|p| match &p.data {
587                SubpacketData::KeyFlags(d) => Some(d[..].into()),
588                _ => None,
589            })
590            .unwrap_or_default()
591    }
592
593    pub fn features(&self) -> &[u8] {
594        self.config
595            .hashed_subpackets()
596            .find_map(|p| match &p.data {
597                SubpacketData::Features(d) => Some(&d[..]),
598                _ => None,
599            })
600            .unwrap_or_else(|| &[][..])
601    }
602
603    pub fn revocation_reason_code(&self) -> Option<&RevocationCode> {
604        self.config.hashed_subpackets().find_map(|p| match &p.data {
605            SubpacketData::RevocationReason(code, _) => Some(code),
606            _ => None,
607        })
608    }
609
610    pub fn revocation_reason_string(&self) -> Option<&BStr> {
611        self.config.hashed_subpackets().find_map(|p| match &p.data {
612            SubpacketData::RevocationReason(_, reason) => Some(reason.as_ref()),
613            _ => None,
614        })
615    }
616
617    pub fn is_primary(&self) -> bool {
618        self.config
619            .hashed_subpackets()
620            .find_map(|p| match &p.data {
621                SubpacketData::IsPrimary(d) => Some(*d),
622                _ => None,
623            })
624            .unwrap_or(false)
625    }
626
627    pub fn is_revocable(&self) -> bool {
628        self.config
629            .hashed_subpackets()
630            .find_map(|p| match &p.data {
631                SubpacketData::Revocable(d) => Some(*d),
632                _ => None,
633            })
634            .unwrap_or(true)
635    }
636
637    pub fn embedded_signature(&self) -> Option<&Signature> {
638        // We consider data from both the hashed and unhashed area here, because the embedded
639        // signature is inherently cryptographically secured. An attacker can't add a valid
640        // embedded signature, canonicalization will remove any invalid embedded signature
641        // subpackets.
642        self.config
643            .hashed_subpackets()
644            .chain(self.config.unhashed_subpackets())
645            .find_map(|p| match &p.data {
646                SubpacketData::EmbeddedSignature(d) => Some(&**d),
647                _ => None,
648            })
649    }
650
651    pub fn preferred_key_server(&self) -> Option<&str> {
652        self.config.hashed_subpackets().find_map(|p| match &p.data {
653            SubpacketData::PreferredKeyServer(d) => Some(d.as_str()),
654            _ => None,
655        })
656    }
657
658    pub fn notations(&self) -> Vec<&Notation> {
659        self.config
660            .hashed_subpackets()
661            .filter_map(|p| match &p.data {
662                SubpacketData::Notation(d) => Some(d),
663                _ => None,
664            })
665            .collect()
666    }
667
668    pub fn revocation_key(&self) -> Option<&types::RevocationKey> {
669        self.config.hashed_subpackets().find_map(|p| match &p.data {
670            SubpacketData::RevocationKey(d) => Some(d),
671            _ => None,
672        })
673    }
674
675    /// Gets the user id of the signer
676    ///
677    /// Note that the user id may not be valid utf-8, if it was created
678    /// using a different encoding. But since the RFC describes every
679    /// text as utf-8 it is up to the caller whether to error on non utf-8 data.
680    pub fn signers_userid(&self) -> Option<&BStr> {
681        self.config.hashed_subpackets().find_map(|p| match &p.data {
682            SubpacketData::SignersUserID(d) => Some(d.as_ref()),
683            _ => None,
684        })
685    }
686
687    pub fn policy_uri(&self) -> Option<&str> {
688        self.config.hashed_subpackets().find_map(|p| match &p.data {
689            SubpacketData::PolicyURI(d) => Some(d.as_ref()),
690            _ => None,
691        })
692    }
693
694    pub fn trust_signature(&self) -> Option<(u8, u8)> {
695        self.config.hashed_subpackets().find_map(|p| match &p.data {
696            SubpacketData::TrustSignature(depth, value) => Some((*depth, *value)),
697            _ => None,
698        })
699    }
700
701    pub fn regular_expression(&self) -> Option<&BStr> {
702        self.config.hashed_subpackets().find_map(|p| match &p.data {
703            SubpacketData::RegularExpression(d) => Some(d.as_ref()),
704            _ => None,
705        })
706    }
707
708    pub fn exportable_certification(&self) -> bool {
709        self.config
710            .hashed_subpackets()
711            .find_map(|p| match &p.data {
712                SubpacketData::ExportableCertification(d) => Some(*d),
713                _ => None,
714            })
715            .unwrap_or(true)
716    }
717}
718
719#[derive(Debug, PartialEq, Eq, Clone, Copy, FromPrimitive, IntoPrimitive)]
720#[repr(u8)]
721pub enum SignatureVersion {
722    /// Deprecated
723    V2 = 2,
724    V3 = 3,
725    V4 = 4,
726    V5 = 5,
727    V6 = 6,
728
729    #[num_enum(catch_all)]
730    Other(u8),
731}
732
733impl Default for SignatureVersion {
734    fn default() -> Self {
735        Self::V4
736    }
737}
738
739#[derive(Debug, PartialEq, Eq, Copy, Clone, FromPrimitive, IntoPrimitive)]
740#[repr(u8)]
741pub enum SignatureType {
742    /// Signature of a binary document.
743    /// This means the signer owns it, created it, or certifies that it has not been modified.
744    Binary = 0x00,
745    /// Signature of a canonical text document.
746    /// This means the signer owns it, created it, or certifies that it
747    /// has not been modified.  The signature is calculated over the text
748    /// data with its line endings converted to `<CR><LF>`.
749    Text = 0x01,
750    /// Standalone signature.
751    /// This signature is a signature of only its own subpacket contents.
752    /// It is calculated identically to a signature over a zero-length
753    /// binary document.  Note that it doesn't make sense to have a V3 standalone signature.
754    Standalone = 0x02,
755    /// Generic certification of a User ID and Public-Key packet.
756    /// The issuer of this certification does not make any particular
757    /// assertion as to how well the certifier has checked that the owner
758    /// of the key is in fact the person described by the User ID.
759    CertGeneric = 0x10,
760    /// Persona certification of a User ID and Public-Key packet.
761    /// The issuer of this certification has not done any verification of
762    /// the claim that the owner of this key is the User ID specified.
763    CertPersona = 0x11,
764    /// Casual certification of a User ID and Public-Key packet.
765    /// The issuer of this certification has done some casual
766    /// verification of the claim of identity.
767    CertCasual = 0x12,
768    /// Positive certification of a User ID and Public-Key packet.
769    /// The issuer of this certification has done substantial
770    /// verification of the claim of identity.
771    ///
772    /// Most OpenPGP implementations make their "key signatures" as 0x10
773    /// certifications.  Some implementations can issue 0x11-0x13
774    /// certifications, but few differentiate between the types.
775    CertPositive = 0x13,
776    /// Subkey Binding Signature
777    /// This signature is a statement by the top-level signing key that
778    /// indicates that it owns the subkey.  This signature is calculated
779    /// directly on the primary key and subkey, and not on any User ID or
780    /// other packets.  A signature that binds a signing subkey MUST have
781    /// an Embedded Signature subpacket in this binding signature that
782    /// contains a 0x19 signature made by the signing subkey on the
783    /// primary key and subkey.
784    SubkeyBinding = 0x18,
785    /// Primary Key Binding Signature
786    /// This signature is a statement by a signing subkey, indicating
787    /// that it is owned by the primary key and subkey.  This signature
788    /// is calculated the same way as a 0x18 signature: directly on the
789    /// primary key and subkey, and not on any User ID or other packets.
790    KeyBinding = 0x19,
791    /// Signature directly on a key
792    /// This signature is calculated directly on a key.  It binds the
793    /// information in the Signature subpackets to the key, and is
794    /// appropriate to be used for subpackets that provide information
795    /// about the key, such as the Revocation Key subpacket.  It is also
796    /// appropriate for statements that non-self certifiers want to make
797    /// about the key itself, rather than the binding between a key and a name.
798    Key = 0x1F,
799    /// Key revocation signature
800    /// The signature is calculated directly on the key being revoked.  A
801    /// revoked key is not to be used.  Only revocation signatures by the
802    /// key being revoked, or by an authorized revocation key, should be
803    /// considered valid revocation signatures.
804    KeyRevocation = 0x20,
805    /// Subkey revocation signature
806    /// The signature is calculated directly on the subkey being revoked.
807    /// A revoked subkey is not to be used.  Only revocation signatures
808    /// by the top-level signature key that is bound to this subkey, or
809    /// by an authorized revocation key, should be considered valid
810    /// revocation signatures.
811    SubkeyRevocation = 0x28,
812    /// Certification revocation signature
813    /// This signature revokes an earlier User ID certification signature
814    /// (signature class 0x10 through 0x13) or direct-key signature
815    /// (0x1F).  It should be issued by the same key that issued the
816    /// revoked signature or an authorized revocation key.  The signature
817    /// is computed over the same data as the certificate that it
818    /// revokes, and should have a later creation date than that
819    /// certificate.
820    CertRevocation = 0x30,
821    /// Timestamp signature.
822    /// This signature is only meaningful for the timestamp contained in
823    /// it.
824    Timestamp = 0x40,
825    /// Third-Party Confirmation signature.
826    /// This signature is a signature over some other OpenPGP Signature
827    /// packet(s).  It is analogous to a notary seal on the signed data.
828    /// A third-party signature SHOULD include Signature Target
829    /// subpacket(s) to give easy identification.  Note that we really do
830    /// mean SHOULD.  There are plausible uses for this (such as a blind
831    /// party that only sees the signature, not the key or source
832    /// document) that cannot include a target subpacket.
833    ThirdParty = 0x50,
834
835    #[num_enum(catch_all)]
836    Other(u8),
837}
838
839#[derive(Debug, PartialEq, Eq, Copy, Clone)]
840/// Available signature subpacket types
841pub enum SubpacketType {
842    SignatureCreationTime,
843    SignatureExpirationTime,
844    ExportableCertification,
845    TrustSignature,
846    RegularExpression,
847    Revocable,
848    KeyExpirationTime,
849    PreferredSymmetricAlgorithms,
850    RevocationKey,
851    Issuer,
852    Notation,
853    PreferredHashAlgorithms,
854    PreferredCompressionAlgorithms,
855    KeyServerPreferences,
856    PreferredKeyServer,
857    PrimaryUserId,
858    PolicyURI,
859    KeyFlags,
860    SignersUserID,
861    RevocationReason,
862    Features,
863    SignatureTarget,
864    EmbeddedSignature,
865    IssuerFingerprint,
866    PreferredEncryptionModes, // non-RFC, may only be 1: EAX, 2: OCB
867    IntendedRecipientFingerprint,
868    // AttestedCertifications, // non-RFC
869    // KeyBlock,               // non-RFC
870    PreferredAead,
871    Experimental(u8),
872    Other(u8),
873}
874
875impl SubpacketType {
876    pub fn as_u8(&self, is_critical: bool) -> u8 {
877        let raw: u8 = match self {
878            SubpacketType::SignatureCreationTime => 2,
879            SubpacketType::SignatureExpirationTime => 3,
880            SubpacketType::ExportableCertification => 4,
881            SubpacketType::TrustSignature => 5,
882            SubpacketType::RegularExpression => 6,
883            SubpacketType::Revocable => 7,
884            SubpacketType::KeyExpirationTime => 9,
885            SubpacketType::PreferredSymmetricAlgorithms => 11,
886            SubpacketType::RevocationKey => 12,
887            SubpacketType::Issuer => 16,
888            SubpacketType::Notation => 20,
889            SubpacketType::PreferredHashAlgorithms => 21,
890            SubpacketType::PreferredCompressionAlgorithms => 22,
891            SubpacketType::KeyServerPreferences => 23,
892            SubpacketType::PreferredKeyServer => 24,
893            SubpacketType::PrimaryUserId => 25,
894            SubpacketType::PolicyURI => 26,
895            SubpacketType::KeyFlags => 27,
896            SubpacketType::SignersUserID => 28,
897            SubpacketType::RevocationReason => 29,
898            SubpacketType::Features => 30,
899            SubpacketType::SignatureTarget => 31,
900            SubpacketType::EmbeddedSignature => 32,
901            SubpacketType::IssuerFingerprint => 33,
902            SubpacketType::PreferredEncryptionModes => 34,
903            SubpacketType::IntendedRecipientFingerprint => 35,
904            // SubpacketType::AttestedCertifications => 37,
905            // SubpacketType::KeyBlock => 38,
906            SubpacketType::PreferredAead => 39,
907            SubpacketType::Experimental(n) => *n,
908            SubpacketType::Other(n) => *n,
909        };
910
911        if is_critical {
912            // set critical bit
913            raw | 0b1000_0000
914        } else {
915            raw
916        }
917    }
918
919    #[inline]
920    pub fn from_u8(n: u8) -> (Self, bool) {
921        let is_critical = (n >> 7) == 1;
922        // remove critical bit
923        let n = n & 0b0111_1111;
924
925        let m = match n {
926            2 => SubpacketType::SignatureCreationTime,
927            3 => SubpacketType::SignatureExpirationTime,
928            4 => SubpacketType::ExportableCertification,
929            5 => SubpacketType::TrustSignature,
930            6 => SubpacketType::RegularExpression,
931            7 => SubpacketType::Revocable,
932            9 => SubpacketType::KeyExpirationTime,
933            11 => SubpacketType::PreferredSymmetricAlgorithms,
934            12 => SubpacketType::RevocationKey,
935            16 => SubpacketType::Issuer,
936            20 => SubpacketType::Notation,
937            21 => SubpacketType::PreferredHashAlgorithms,
938            22 => SubpacketType::PreferredCompressionAlgorithms,
939            23 => SubpacketType::KeyServerPreferences,
940            24 => SubpacketType::PreferredKeyServer,
941            25 => SubpacketType::PrimaryUserId,
942            26 => SubpacketType::PolicyURI,
943            27 => SubpacketType::KeyFlags,
944            28 => SubpacketType::SignersUserID,
945            29 => SubpacketType::RevocationReason,
946            30 => SubpacketType::Features,
947            31 => SubpacketType::SignatureTarget,
948            32 => SubpacketType::EmbeddedSignature,
949            33 => SubpacketType::IssuerFingerprint,
950            34 => SubpacketType::PreferredEncryptionModes,
951            35 => SubpacketType::IntendedRecipientFingerprint,
952            // 37 => SubpacketType::AttestedCertifications,
953            // 38 => SubpacketType::KeyBlock,
954            39 => SubpacketType::PreferredAead,
955            100..=110 => SubpacketType::Experimental(n),
956            _ => SubpacketType::Other(n),
957        };
958
959        (m, is_critical)
960    }
961}
962
963#[derive(Debug, PartialEq, Eq, Clone)]
964pub struct Subpacket {
965    pub is_critical: bool,
966    pub data: SubpacketData,
967}
968
969impl Subpacket {
970    /// Construct a new regular subpacket.
971    pub const fn regular(data: SubpacketData) -> Self {
972        Subpacket {
973            is_critical: false,
974            data,
975        }
976    }
977
978    /// Construct a new critical subpacket.
979    pub const fn critical(data: SubpacketData) -> Self {
980        Subpacket {
981            is_critical: true,
982            data,
983        }
984    }
985}
986
987#[derive(derive_more::Debug, PartialEq, Eq, Clone)]
988pub enum SubpacketData {
989    /// The time the signature was made.
990    SignatureCreationTime(DateTime<Utc>),
991    /// The time the signature will expire.
992    SignatureExpirationTime(Duration),
993    /// When the key is going to expire
994    KeyExpirationTime(Duration),
995    /// The OpenPGP Key ID of the key issuing the signature.
996    Issuer(KeyId),
997    /// List of symmetric algorithms that indicate which algorithms the key holder prefers to use.
998    /// Renamed to "Preferred Symmetric Ciphers for v1 SEIPD" in RFC 9580
999    PreferredSymmetricAlgorithms(SmallVec<[SymmetricKeyAlgorithm; 8]>),
1000    /// List of hash algorithms that indicate which algorithms the key holder prefers to use.
1001    PreferredHashAlgorithms(SmallVec<[HashAlgorithm; 8]>),
1002    /// List of compression algorithms that indicate which algorithms the key holder prefers to use.
1003    PreferredCompressionAlgorithms(SmallVec<[CompressionAlgorithm; 8]>),
1004    KeyServerPreferences(#[debug("{}", hex::encode(_0))] SmallVec<[u8; 4]>),
1005    KeyFlags(#[debug("{}", hex::encode(_0))] SmallVec<[u8; 1]>),
1006    Features(#[debug("{}", hex::encode(_0))] SmallVec<[u8; 1]>),
1007    RevocationReason(RevocationCode, BString),
1008    IsPrimary(bool),
1009    Revocable(bool),
1010    EmbeddedSignature(Box<Signature>),
1011    PreferredKeyServer(String),
1012    Notation(Notation),
1013    RevocationKey(types::RevocationKey),
1014    SignersUserID(BString),
1015    /// The URI of the policy under which the signature was issued
1016    PolicyURI(String),
1017    TrustSignature(u8, u8),
1018    RegularExpression(BString),
1019    ExportableCertification(bool),
1020    IssuerFingerprint(Fingerprint),
1021    PreferredEncryptionModes(SmallVec<[AeadAlgorithm; 2]>),
1022    IntendedRecipientFingerprint(Fingerprint),
1023    PreferredAeadAlgorithms(SmallVec<[(SymmetricKeyAlgorithm, AeadAlgorithm); 4]>),
1024    Experimental(u8, #[debug("{}", hex::encode(_1))] SmallVec<[u8; 2]>),
1025    Other(u8, #[debug("{}", hex::encode(_1))] Vec<u8>),
1026    SignatureTarget(
1027        PublicKeyAlgorithm,
1028        HashAlgorithm,
1029        #[debug("{}", hex::encode(_2))] Vec<u8>,
1030    ),
1031}
1032
1033bitfield! {
1034    #[derive(Default, PartialEq, Eq, Copy, Clone)]
1035    pub struct KeyFlags(u8);
1036    impl Debug;
1037
1038    pub certify, set_certify: 0;
1039    pub sign, set_sign: 1;
1040    pub encrypt_comms, set_encrypt_comms: 2;
1041    pub encrypt_storage, set_encrypt_storage: 3;
1042    pub shared, set_shared: 4;
1043    pub authentication, set_authentication: 5;
1044    pub group, set_group: 7;
1045}
1046
1047impl<'a> From<&'a [u8]> for KeyFlags {
1048    fn from(other: &'a [u8]) -> Self {
1049        if other.is_empty() {
1050            Default::default()
1051        } else {
1052            KeyFlags(other[0])
1053        }
1054    }
1055}
1056
1057impl From<KeyFlags> for SmallVec<[u8; 1]> {
1058    fn from(flags: KeyFlags) -> Self {
1059        smallvec![flags.0]
1060    }
1061}
1062
1063#[derive(Debug, PartialEq, Eq, Clone)]
1064pub struct Notation {
1065    pub readable: bool,
1066    pub name: BString,
1067    pub value: BString,
1068}
1069
1070/// Codes for revocation reasons
1071#[derive(Debug, PartialEq, Eq, Copy, Clone, FromPrimitive, IntoPrimitive)]
1072#[repr(u8)]
1073pub enum RevocationCode {
1074    /// No reason specified (key revocations or cert revocations)
1075    NoReason = 0,
1076    /// Key is superseded (key revocations)
1077    KeySuperseded = 1,
1078    /// Key material has been compromised (key revocations)
1079    KeyCompromised = 2,
1080    /// Key is retired and no longer used (key revocations)
1081    KeyRetired = 3,
1082    /// User ID information is no longer valid (cert revocations)
1083    CertUserIdInvalid = 32,
1084
1085    /// Private Use range (from OpenPGP)
1086    Private100 = 100,
1087    Private101 = 101,
1088    Private102 = 102,
1089    Private103 = 103,
1090    Private104 = 104,
1091    Private105 = 105,
1092    Private106 = 106,
1093    Private107 = 107,
1094    Private108 = 108,
1095    Private109 = 109,
1096    Private110 = 110,
1097
1098    /// Undefined code
1099    #[num_enum(catch_all)]
1100    Other(u8),
1101}
1102
1103impl PacketTrait for Signature {
1104    fn packet_version(&self) -> Version {
1105        self.packet_version
1106    }
1107
1108    fn tag(&self) -> Tag {
1109        Tag::Signature
1110    }
1111}
1112
1113#[cfg(test)]
1114mod tests {
1115    use super::*;
1116
1117    #[test]
1118    fn test_keyflags() {
1119        let flags: KeyFlags = Default::default();
1120        assert_eq!(flags.0, 0x00);
1121
1122        let mut flags = KeyFlags::default();
1123        flags.set_certify(true);
1124        assert!(flags.certify());
1125        assert_eq!(flags.0, 0x01);
1126
1127        let mut flags = KeyFlags::default();
1128        flags.set_sign(true);
1129        assert_eq!(flags.0, 0x02);
1130
1131        let mut flags = KeyFlags::default();
1132        flags.set_encrypt_comms(true);
1133        assert_eq!(flags.0, 0x04);
1134
1135        let mut flags = KeyFlags::default();
1136        flags.set_encrypt_storage(true);
1137        assert_eq!(flags.0, 0x08);
1138
1139        let mut flags = KeyFlags::default();
1140        flags.set_shared(true);
1141        assert_eq!(flags.0, 0x10);
1142
1143        let mut flags = KeyFlags::default();
1144        flags.set_authentication(true);
1145        assert_eq!(flags.0, 0x20);
1146
1147        let mut flags = KeyFlags::default();
1148        flags.set_group(true);
1149        assert_eq!(flags.0, 0x80);
1150    }
1151
1152    #[test]
1153    fn test_critical() {
1154        use SubpacketType::*;
1155
1156        let cases = [
1157            SignatureCreationTime,
1158            SignatureExpirationTime,
1159            ExportableCertification,
1160            TrustSignature,
1161            RegularExpression,
1162            Revocable,
1163            KeyExpirationTime,
1164            PreferredSymmetricAlgorithms,
1165            RevocationKey,
1166            Issuer,
1167            Notation,
1168            PreferredHashAlgorithms,
1169            PreferredCompressionAlgorithms,
1170            KeyServerPreferences,
1171            PreferredKeyServer,
1172            PrimaryUserId,
1173            PolicyURI,
1174            KeyFlags,
1175            SignersUserID,
1176            RevocationReason,
1177            Features,
1178            SignatureTarget,
1179            EmbeddedSignature,
1180            IssuerFingerprint,
1181            PreferredAead,
1182            Experimental(101),
1183            Other(95),
1184        ];
1185        for case in cases {
1186            assert_eq!(SubpacketType::from_u8(case.as_u8(false)), (case, false));
1187            assert_eq!(SubpacketType::from_u8(case.as_u8(true)), (case, true));
1188        }
1189    }
1190}