Skip to main content

sequoia_openpgp/
policy.rs

1//! A mechanism to specify policy.
2//!
3//! A major goal of the Sequoia OpenPGP crate is to be policy free.
4//! However, many mid-level operations build on low-level primitives.
5//! For instance, finding a certificate's primary User ID means
6//! examining each of its User IDs and their current self-signature.
7//! Some algorithms are considered broken (e.g., MD5) and some are
8//! considered weak (e.g. SHA-1).  When dealing with data from an
9//! untrusted source, for instance, callers will often prefer to
10//! ignore signatures that rely on these algorithms even though [RFC
11//! 4880] says that "\[i\]mplementations MUST implement SHA-1."  When
12//! trying to decrypt old archives, however, users probably don't want
13//! to ignore keys using MD5, even though [Section 9.5 of RFC 9580]
14//! deprecates MD5.
15//!
16//! Rather than not provide this mid-level functionality, the `Policy`
17//! trait allows callers to specify their preferred policy.  This can be
18//! highly customized by providing a custom implementation of the
19//! `Policy` trait, or it can be slightly refined by tweaking the
20//! `StandardPolicy`'s parameters.
21//!
22//! When implementing the `Policy` trait, it is *essential* that the
23//! functions are [pure].  That is, if the same `Policy` is used
24//! to determine whether a given `Signature` is valid, it must always
25//! return the same value.
26//!
27//! [Section 9.5 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-9.5
28//! [pure]: https://en.wikipedia.org/wiki/Pure_function
29use std::fmt;
30use std::time::{SystemTime, Duration};
31use std::u32;
32
33use anyhow::Context;
34
35use crate::{
36    cert::prelude::*,
37    Error,
38    Packet,
39    packet::{
40        key,
41        Signature,
42        signature::subpacket::{
43            SubpacketTag,
44            SubpacketValue,
45        },
46        Tag,
47    },
48    Result,
49    types,
50    types::{
51        AEADAlgorithm,
52        HashAlgorithm,
53        SignatureType,
54        SymmetricAlgorithm,
55        Timestamp,
56    },
57};
58
59#[macro_use] mod cutofflist;
60use cutofflist::{
61    CutoffList,
62    REJECT,
63    ACCEPT,
64    VersionedCutoffList,
65};
66
67/// A policy for cryptographic operations.
68pub trait Policy : fmt::Debug + Send + Sync {
69    /// Returns an error if the signature violates the policy.
70    ///
71    /// This function performs the last check before the library
72    /// decides that a signature is valid.  That is, after the library
73    /// has determined that the signature is well-formed, alive, not
74    /// revoked, etc., it calls this function to allow you to
75    /// implement any additional policy.  For instance, you may reject
76    /// signatures that make use of cryptographically insecure
77    /// algorithms like SHA-1.
78    ///
79    /// Note: Whereas it is generally better to reject suspicious
80    /// signatures, one should be more liberal when considering
81    /// revocations: if you reject a revocation certificate, it may
82    /// inadvertently make something else valid!
83    fn signature(&self, _sig: &Signature, _sec: HashAlgoSecurity) -> Result<()> {
84        Err(Error::PolicyViolation(
85            "By default all signatures are rejected.".into(), None).into())
86    }
87
88    /// Returns an error if the key violates the policy.
89    ///
90    /// This function performs one of the last checks before a
91    /// `KeyAmalgamation` or a related data structures is turned into
92    /// a `ValidKeyAmalgamation`, or similar.
93    ///
94    /// Internally, the library always does this before using a key.
95    /// The sole exception is when creating a key using `CertBuilder`.
96    /// In that case, the primary key is not validated before it is
97    /// used to create any binding signatures.
98    ///
99    /// Thus, you can prevent keys that make use of insecure
100    /// algorithms, don't have a sufficiently high security margin
101    /// (e.g., 1024-bit RSA keys), are on a bad list, etc. from being
102    /// used here.
103    ///
104    /// If you implement this function, make sure to consider the Key
105    /// Derivation Function and Key Encapsulation parameters of ECDH
106    /// keys, see [`PublicKey::ECDH`].
107    ///
108    /// [`PublicKey::ECDH`]: crate::crypto::mpi::PublicKey::ECDH
109    fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
110        -> Result<()>
111    {
112        Err(Error::PolicyViolation(
113            "By default all keys are rejected.".into(), None).into())
114    }
115
116    /// Returns an error if the symmetric encryption algorithm
117    /// violates the policy.
118    ///
119    /// This function performs the last check before an encryption
120    /// container is decrypted by the streaming decryptor.
121    ///
122    /// With this function, you can prevent the use of insecure
123    /// symmetric encryption algorithms.
124    fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
125        Err(Error::PolicyViolation(
126            "By default all symmetric algorithms are rejected.".into(), None).into())
127    }
128
129    /// Returns an error if the AEAD mode violates the policy.
130    ///
131    /// This function performs the last check before an encryption
132    /// container is decrypted by the streaming decryptor.
133    ///
134    /// With this function, you can prevent the use of insecure AEAD
135    /// constructions.
136    ///
137    /// This feature is [experimental](super#experimental-features).
138    fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
139        Err(Error::PolicyViolation(
140            "By default all AEAD algorithms are rejected.".into(), None).into())
141    }
142
143    /// Returns an error if the packet violates the policy.
144    ///
145    /// This function performs the last check before a packet is
146    /// considered by the streaming verifier and decryptor.
147    ///
148    /// With this function, you can prevent the use of insecure
149    /// encryption containers, notably the *Symmetrically Encrypted
150    /// Data Packet*.
151    fn packet(&self, _packet: &Packet) -> Result<()> {
152        Err(Error::PolicyViolation(
153            "By default all packets are rejected.".into(), None).into())
154    }
155}
156
157/// Whether the signed data requires a hash algorithm with collision
158/// resistance.
159///
160/// Since the context of a signature is not passed to
161/// `Policy::signature`, it is not possible to determine from that
162/// function whether the signature requires a hash algorithm with
163/// collision resistance.  This enum indicates this.
164///
165/// In short, many self signatures only require second pre-image
166/// resistance.  This can be used to extend the life of hash
167/// algorithms whose collision resistance has been partially
168/// compromised.  Be careful.  Read the background and the warning
169/// before accepting the use of weak hash algorithms!
170///
171/// # Warning
172///
173/// Although distinguishing whether signed data requires collision
174/// resistance can be used to permit the continued use of a hash
175/// algorithm in certain situations, once attacks against a hash
176/// algorithm are known, it is imperative to retire the use of the
177/// hash algorithm as soon as it is feasible.  Cryptoanalytic attacks
178/// improve quickly, as demonstrated by the attacks on SHA-1.
179///
180/// # Background
181///
182/// Cryptographic hash functions normally have three security
183/// properties:
184///
185///   - Pre-image resistance,
186///   - Second pre-image resistance, and
187///   - Collision resistance.
188///
189/// A hash algorithm has pre-image resistance if given a hash `h`, it
190/// is impractical for an attacker to find a message `m` such that `h
191/// = hash(m)`.  In other words, a hash algorithm has pre-image
192/// resistance if it is hard to invert.  A hash algorithm has second
193/// pre-image resistance if it is impractical for an attacker to find
194/// a second message with the same hash as the first.  That is, given
195/// `m1`, it is hard for an attacker to find an `m2` such that
196/// `hash(m1) = hash(m2)`.  And, a hash algorithm has collision
197/// resistance if it is impractical for an attacker to find two
198/// messages with the same hash.  That is, it is hard for an attacker
199/// to find an `m1` and an `m2` such that `hash(m1) = hash(m2)`.
200///
201/// In the context of verifying an OpenPGP signature, we don't need a
202/// hash algorithm with pre-image resistance.  Pre-image resistance is
203/// only required when the message is a secret, e.g., a password.  We
204/// always need a hash algorithm with second pre-image resistance,
205/// because an attacker must not be able to repurpose an arbitrary
206/// signature, i.e., create a collision with respect to a *known*
207/// hash.  And, we need collision resistance when a signature is over
208/// data that could have been influenced by an attacker: if an
209/// attacker creates a pair of colliding messages and convinces the
210/// user to sign one of them, then the attacker can copy the signature
211/// to the other message.
212///
213/// Collision resistance implies second pre-image resistance, but not
214/// vice versa.  If an attacker can find a second message with the
215/// same hash as some known message, they can also create a collision
216/// by choosing an arbitrary message and using their pre-image attack
217/// to find a colliding message.  Thus, a context that requires
218/// collision resistance also requires second pre-image resistance.
219///
220/// Because collision resistance is with respect to two arbitrary
221/// messages, collision resistance is always susceptible to a
222/// [birthday paradox].  This means that the security margin of a hash
223/// algorithm's collision resistance is half of the security margin of
224/// its second pre-image resistance.  And, in practice, the collision
225/// resistance of industry standard hash algorithms has been
226/// practically attacked multiple times.  In the context of SHA-1,
227/// Wang et al. described how to find collisions in SHA-1 in their
228/// 2005 paper [Finding Collisions in the Full SHA-1].  In 2017,
229/// Stevens et al. published [The First Collision for Full SHA-1],
230/// which demonstrates the first practical attack on SHA-1's collision
231/// resistance, an identical-prefix collision attack.  This attack
232/// only gives the attacker limited control over the content of the
233/// collided messages, which limits its applicability.  However, in
234/// 2020, Leurent and Peyrin published [SHA-1 is a Shambles], which
235/// demonstrates a practical chosen-prefix collision attack.  This
236/// attack gives the attacker complete control over the prefixes of
237/// the collided messages.
238///
239///   [birthday paradox]: https://en.wikipedia.org/wiki/Birthday_attack#Digital_signature_susceptibility
240///   [Finding Collisions in the Full SHA-1]: https://link.springer.com/chapter/10.1007/11535218_2
241///   [The first collision for full SHA-1]: https://shattered.io/
242///   [SHA-1 is a Shambles]: https://sha-mbles.github.io/
243///
244/// A chosen-prefix collision attack works as follows: an attacker
245/// chooses two arbitrary message prefixes, and then searches for
246/// so-called near collision blocks.  These near collision blocks
247/// cause the internal state of the hashes to converge and eventually
248/// result in a collision, i.e., an identical hash value.  The attack
249/// described in the [SHA-1 is a Shambles] paper requires 8 to 10 near
250/// collision blocks (512 to 640 bytes) to fully synchronize the
251/// internal state.
252///
253/// SHA-1 is a [Merkle-Damgård hash function].  This means that the
254/// hash function processes blocks one after the other, and the
255/// internal state of the hash function at any given point only
256/// depends on earlier blocks in the stream.  A consequence of this is
257/// that it is possible to append a common suffix to the collided
258/// messages without any additional computational effort.  That is, if
259/// `hash(m1) = hash(m2)`, then it necessarily holds that `hash(m1 ||
260/// suffix) = hash(m2 || suffix)`.  This is called a [length extension
261/// attack].
262///
263///   [Merkle-Damgård hash function]: https://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction
264///   [length extension attack]: https://en.wikipedia.org/wiki/Length_extension_attack
265///
266/// Thus, the [SHA-1 is a Shambles] attack solves the following:
267///
268/// ```text
269/// hash(m1 || collision blocks 1 || suffix) = hash(m2 || collision blocks 2 || suffix)
270/// ```
271///
272/// Where `m1`, `m2`, and `suffix` are controlled by the attacker, and
273/// only the collision blocks are controlled by the algorithm.
274///
275/// If an attacker can convince an OpenPGP user to sign a message of
276/// their choosing (some `m1 || collision blocks 1 || suffix`), then
277/// the attacker also has a valid signature from the victim for a
278/// colliding message (some `m2 || collision blocks 2 || suffix`).
279///
280/// The OpenPGP format imposes some additional constraints on the
281/// attacker.  Although the attacker may control the message, the
282/// signature is also over a [signature packet], and a trailer.
283/// Specifically, [the following is signed] when signing a document:
284///
285/// ```text
286/// hash(document || sig packet || 0x04 || sig packet len)
287/// ```
288///
289/// and the [following is signed] when signing a binding signature:
290///
291/// ```text
292/// hash(public key || subkey || sig packet || 0x04 || sig packet len)
293/// ```
294///
295///  [signature packet]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3
296///  [the following is signed]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.4
297///
298/// Since the signature packet is chosen by the victim's OpenPGP
299/// implementation, the attacker may be able to predict it, but they
300/// cannot store the collision blocks there.  Thus, the signature
301/// packet is necessarily part of the common suffix, and the collision
302/// blocks must occur earlier in the stream.
303///
304/// This restriction on the signature packet means that an attacker
305/// cannot convince the victim to sign a document, and then transfer
306/// that signature to a colliding binding signature.  These signatures
307/// necessarily have different [signature packet]s: the value of the
308/// [signature type] field is different.  And, as just described, for
309/// this attack, the signature packets must be identical, because they
310/// are part of the common suffix.  Finally, the trailer, which
311/// contains the signature packet's length, prevents hiding a
312/// signature in a signature.
313///
314///   [signature type]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
315///
316/// Given this, if we know for a given signature type that an attacker
317/// cannot control any of the data that is signed, then that type of
318/// signature does not need collision resistance; it is still
319/// vulnerable to an attack on the hash's second pre-image resistance
320/// (a collision with a specific message), but not one on its
321/// collision resistance (a collision with any message).  This is the
322/// case for binding signatures, and direct key signatures.  But, it
323/// is not normally the case for documents (the attacker may be able
324/// to control the content of the document), certifications (the
325/// attacker may be able to control the key packet, the User ID
326/// packet, or the User Attribute packet), or certificate revocations
327/// (the attacker may be able to control the key packet).
328///
329/// Certification signatures and revocations signatures can be further
330/// divided into self signatures and third-party signatures.  If an
331/// attacker can convince a victim into signing a third-party
332/// signature, as was done in the [SHA-1 is a Shambles], they may be
333/// able to transfer the signature to a colliding self signature.  If
334/// we can show that an attacker can't collide a self signature, and a
335/// third-party signature, then we may be able to show that self
336/// signatures don't require collision resistance.  The same
337/// consideration holds for revocations and third-party revocations.
338///
339/// We first consider revocations, which are more straightforward.
340/// The attack is the following: an attacker creates a fake
341/// certificate (A), and sets the victim as a designated revoker.
342/// They then ask the victim to revoke their certificate (V).  The
343/// attacker than transfers the signature to a colliding self
344/// revocation, which causes the victim's certificate (V) to be
345/// revoked.
346///
347/// A revocation is over a public key packet and a signature packet.
348/// In this scenario, the attacker controls the fake certificate (A)
349/// and thus the public key packet that the victim actually signs.
350/// But the victim's public key packet is determined by their
351/// certificate (V).  Thus, the attacker would have to insert the near
352/// collision blocks in the signature packet, which, as we argued
353/// before, is not possible.  Thus, it is safe to only use a hash with
354/// pre-image resistance to protect a self-revocation.
355///
356/// We now turn to self signatures.  The attack is similar to the
357/// [SHA-1 is a Shambles] attack.  An attacker creates a certificate
358/// (A) and convinces the victim to sign it.  The attacker can then
359/// transfer the third-party certification to a colliding self
360/// signature for the victim's certificate (V).  If successful, this
361/// attack allows the attacker to add a User ID or a User Attribute to
362/// the victim's certificate (V).  This can confuse people who use the
363/// victim's certificate.  For instance, if the attacker adds the
364/// identity `alice@example.org` to the victim's certificate, and Bob
365/// receives a message signed using the victim's certificate (V), he
366/// may think that Alice signed the message instead of the victim.
367/// Bob won't be tricked if he uses strong authentication, but many
368/// OpenPGP users use weak authentication (e.g., TOFU) or don't
369/// authenticate keys at all.
370///
371/// A certification is over a public key packet, a User ID or User
372/// Attribute packet, and a signature packet.  The attacker controls
373/// the fake certificate (A) and therefore the public key packet, and
374/// the User ID or User Attribute packet that the victim signs.
375/// However, to trick the victim, the User ID packet or User Attribute
376/// packet needs to correspond to an identity that the attacker
377/// appears to control.  Thus, if the near collision blocks are stored
378/// in the User ID or User Attribute packet of A, they have to be
379/// hidden to avoid making the victim suspicious.  This is
380/// straightforward for User Attributes, which are currently images,
381/// and have many places to hide this type of data.  However, User IDs
382/// are normally [UTF-8 encoded RFC 2822 mailbox]es, which makes
383/// hiding half a kilobyte of binary data impractical.  The attacker
384/// does not control the victim's public key (in V).  But, they do
385/// control the malicious User ID or User Attribute that they want to
386/// attack to the victim's certificate (V).  But again, the near
387/// collision blocks have to be hidden in order to trick Bob, the
388/// second victim.  Thus, the attack has two possibilities: they can
389/// hide the near collision blocks in the fake public key (in A), and
390/// the User ID or User Attribute (added to V); or, they can hide them
391/// in the fake User IDs or User Attributes (in A and the one added to
392/// V).
393///
394/// As evidenced by the [SHA-1 is a Shambles] attack, it is possible
395/// to hide near collision blocks in User Attribute packets.  Thus,
396/// this attack can be used to transfer a third-party certification
397/// over a User Attribute to a self signature over a User Attribute.
398/// As such, self signatures over User Attributes need collision
399/// resistance.
400///
401/// The final case to consider is hiding the near collision blocks in
402/// the User ID that the attacker wants to add to the victim's
403/// certificate.  Again, it is possible to store the near collision
404/// blocks there.  However, there are two mitigating factors.  First,
405/// there is no place to hide the blocks.  As such, the user must be
406/// convinced to ignore them.  Second, a User ID is structure: it
407/// normally contains a [UTF-8 encoded RFC 2822 mailbox].  Thus, if we
408/// only consider valid UTF-8 strings, and limit the maximum size, we
409/// can dramatically increase the workfactor, which can extend the life
410/// of a hash algorithm whose collision resistance has been weakened.
411///
412///   [UTF-8 encoded RFC 2822 mailbox]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.11
413#[derive(Debug, Clone, Copy, Eq, PartialEq)]
414pub enum HashAlgoSecurity {
415    /// The signed data only requires second pre-image resistance.
416    ///
417    /// If a signature is over data that an attacker cannot influence,
418    /// then the hash function does not need to provide collision
419    /// resistance.  This is **only** the case for:
420    ///
421    ///   - Subkey binding signatures
422    ///   - Primary key binding signatures
423    ///   - Self revocations
424    ///
425    /// Due to the structure of User IDs (they are normally short,
426    /// UTF-8 encoded RFC 2822 mailboxes), self signatures over short,
427    /// reasonable User IDs (**not** User Attributes) also don't
428    /// require strong collision resistance.  Thus, we also only
429    /// require a signature with second pre-image resistance for:
430    ///
431    ///   - Self signatures over reasonable User IDs
432    SecondPreImageResistance,
433    /// The signed data requires collision resistance.
434    ///
435    /// If a signature is over data that an attacker can influence,
436    /// then the hash function must provide collision resistance.
437    /// This is the case for documents, third-party certifications,
438    /// and third-party revocations.
439    ///
440    /// Note: collision resistance implies second pre-image
441    /// resistance.  Thus, when evaluating whether a hash algorithm
442    /// has collision resistance, we also check whether it has second
443    /// pre-image resistance.
444    CollisionResistance,
445}
446
447impl Default for HashAlgoSecurity {
448    /// The default is the most conservative policy.
449    fn default() -> Self {
450        HashAlgoSecurity::CollisionResistance
451    }
452}
453
454/// The standard policy.
455///
456/// The standard policy stores when each algorithm in a family of
457/// algorithms is no longer considered safe.  Attempts to use an
458/// algorithm after its cutoff time should fail.
459///
460/// A `StandardPolicy` can be configured using Rust.  Sometimes it is
461/// useful to configure it via a configuration file.  This can be done
462/// using the [`sequoia-policy-config`] crate.
463///
464///   [`sequoia-policy-config`]: https://docs.rs/sequoia-policy-config/latest/sequoia_policy_config/
465///
466/// It is recommended to support using a configuration file when the
467/// program should respect the system's crypto policy.  This is
468/// required on Fedora, for instance.  See the [Fedora Crypto
469/// Policies] project for more information.
470///
471///   [Fedora]: https://gitlab.com/redhat-crypto/fedora-crypto-policies
472///
473/// When validating a signature, we normally want to know whether the
474/// algorithms used are safe *now*.  That is, we don't use the
475/// signature's alleged creation time when considering whether an
476/// algorithm is safe, because if an algorithm is discovered to be
477/// compromised at time X, then an attacker could forge a message
478/// after time X with a signature creation time that is prior to X,
479/// which would be incorrectly accepted.
480///
481/// Occasionally, we know that a signature has not been tampered with
482/// since some time in the past.  We might know this if the signature
483/// was stored on some tamper-proof medium.  In those cases, it is
484/// reasonable to use the time that the signature was saved, since an
485/// attacker could not have taken advantage of any weaknesses found
486/// after that time.
487///
488/// # Examples
489///
490/// A `StandardPolicy` object can be used to build specialized policies.
491/// For example the following policy filters out Persona certifications mimicking
492/// what GnuPG does when calculating the Web of Trust.
493///
494/// ```rust
495/// use sequoia_openpgp as openpgp;
496/// use std::io::{Cursor, Read};
497/// use openpgp::Result;
498/// use openpgp::packet::{Packet, Signature, key::PublicParts};
499/// use openpgp::cert::prelude::*;
500/// use openpgp::parse::Parse;
501/// use openpgp::armor::{Reader, ReaderMode, Kind};
502/// use openpgp::policy::{HashAlgoSecurity, Policy, StandardPolicy};
503/// use openpgp::types::{
504///    SymmetricAlgorithm,
505///    AEADAlgorithm,
506///    SignatureType
507/// };
508///
509/// #[derive(Debug)]
510/// struct RejectPersonaCertificationsPolicy<'a>(StandardPolicy<'a>);
511///
512/// impl Policy for RejectPersonaCertificationsPolicy<'_> {
513///     fn key(&self, ka: &ValidErasedKeyAmalgamation<PublicParts>)
514///            -> Result<()>
515///     {
516///         self.0.key(ka)
517///     }
518///
519///     fn signature(&self, sig: &Signature, sec: HashAlgoSecurity) -> Result<()> {
520///         if sig.typ() == SignatureType::PersonaCertification {
521///             Err(anyhow::anyhow!("Persona certifications are ignored."))
522///         } else {
523///             self.0.signature(sig, sec)
524///         }
525///     }
526///
527///     fn symmetric_algorithm(&self, algo: SymmetricAlgorithm) -> Result<()> {
528///         self.0.symmetric_algorithm(algo)
529///     }
530///
531///     fn aead_algorithm(&self, algo: AEADAlgorithm) -> Result<()> {
532///         self.0.aead_algorithm(algo)
533///     }
534///
535///     fn packet(&self, packet: &Packet) -> Result<()> {
536///         self.0.packet(packet)
537///     }
538/// }
539///
540/// impl RejectPersonaCertificationsPolicy<'_> {
541///     fn new() -> Self {
542///         Self(StandardPolicy::new())
543///     }
544/// }
545///
546/// # fn main() -> Result<()> {
547/// // this key has one persona certification
548/// let data = r#"
549/// -----BEGIN PGP PUBLIC KEY BLOCK-----
550///
551/// mDMEX7JGrxYJKwYBBAHaRw8BAQdASKGcnowaZBDc2Z3rZZlWb6jEjne9sK76afbJ
552/// trd5Uw+0BlRlc3QgMoiQBBMWCAA4FiEEyZ6oBYFia3z+ooCBqR9BqiGp8AQFAl+y
553/// Rq8CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQqR9BqiGp8ASfxwEAvEb0
554/// bFr7ZgFZSDOITNptm+FEynib8mmLACsvHAmCjvIA+gOaSNyxMW6N59q7/j0sDjp1
555/// aYNgpNFLbYBZpkXXVL0GiHUEERYIAB0WIQTE4QfdkkisIbWVOcHmlsuS3dbWEwUC
556/// X7JG4gAKCRDmlsuS3dbWExEwAQCpqfiVMhjDwVFMsMpwd5r0N/8rAx8/nmgpCsK3
557/// M9TUrAD7BhTYVPRbkJqTZYd9DlLtBcbF3yNPTHlB+F2sFjI+cgo=
558/// =ZfYu
559/// -----END PGP PUBLIC KEY BLOCK-----
560/// "#;
561///
562/// let mut cursor = Cursor::new(&data);
563/// let mut reader = Reader::from_reader(&mut cursor, ReaderMode::Tolerant(Some(Kind::PublicKey)));
564///
565/// let mut buf = Vec::new();
566/// reader.read_to_end(&mut buf)?;
567/// let cert = Cert::from_bytes(&buf)?;
568///
569/// let ref sp = StandardPolicy::new();
570/// let u = cert.with_policy(sp, None)?.userids().nth(0).unwrap();
571///
572/// // Under the standard policy the persona certification is visible.
573/// assert_eq!(u.certifications().count(), 1);
574///
575/// // Under our custom policy the persona certification is not available.
576/// let ref p = RejectPersonaCertificationsPolicy::new();
577/// assert_eq!(u.with_policy(p, None)?.certifications().count(), 0);
578/// #
579/// # Ok(())
580/// # }
581/// ```
582#[derive(Clone, Debug)]
583pub struct StandardPolicy<'a> {
584    // The time.  If None, the current time is used.
585    time: Option<Timestamp>,
586
587    // Hash algorithms.
588    collision_resistant_hash_algos:
589        CollisionResistantHashCutoffList,
590    second_pre_image_resistant_hash_algos:
591        SecondPreImageResistantHashCutoffList,
592    hash_revocation_tolerance: types::Duration,
593
594    // Critical subpacket tags.
595    critical_subpackets: SubpacketTagCutoffList,
596
597    // Critical notation good-list.
598    good_critical_notations: &'a [&'a str],
599
600    // Packet types.
601    packet_tags: PacketTagCutoffList,
602
603    // Symmetric algorithms.
604    symmetric_algos: SymmetricAlgorithmCutoffList,
605
606    // AEAD algorithms.
607    aead_algos: AEADAlgorithmCutoffList,
608
609    // Asymmetric algorithms.
610    asymmetric_algos: AsymmetricAlgorithmCutoffList,
611}
612
613assert_send_and_sync!(StandardPolicy<'_>);
614
615impl<'a> Default for StandardPolicy<'a> {
616    fn default() -> Self {
617        Self::new()
618    }
619}
620
621impl<'a> From<&'a StandardPolicy<'a>> for Option<&'a dyn Policy> {
622    fn from(p: &'a StandardPolicy<'a>) -> Self {
623        Some(p as &dyn Policy)
624    }
625}
626
627// Signatures that require a hash with collision Resistance and second
628// Pre-image Resistance.  See the documentation for HashAlgoSecurity
629// for more details.
630a_cutoff_list!(CollisionResistantHashCutoffList, HashAlgorithm, 15,
631               [
632                   REJECT,                   // 0. Not assigned.
633                   Some(Timestamp::Y1997M2), // 1. MD5
634                   Some(Timestamp::Y2013M2), // 2. SHA-1
635                   Some(Timestamp::Y2013M2), // 3. RIPE-MD/160
636                   REJECT,                   // 4. Reserved.
637                   REJECT,                   // 5. Reserved.
638                   REJECT,                   // 6. Reserved.
639                   REJECT,                   // 7. Reserved.
640                   ACCEPT,                   // 8. SHA256
641                   ACCEPT,                   // 9. SHA384
642                   ACCEPT,                   // 10. SHA512
643                   ACCEPT,                   // 11. SHA224
644                   ACCEPT,                   // 12. SHA3-256
645                   REJECT,                   // 13. Reserved.
646                   ACCEPT,                   // 14. SHA3-512
647               ]);
648// Signatures that *only* require a hash with Second Pre-image
649// Resistance.  See the documentation for HashAlgoSecurity for more
650// details.
651a_cutoff_list!(SecondPreImageResistantHashCutoffList, HashAlgorithm, 15,
652               [
653                   REJECT,                   // 0. Not assigned.
654                   Some(Timestamp::Y2004M2), // 1. MD5
655                   Some(Timestamp::Y2023M2), // 2. SHA-1
656                   Some(Timestamp::Y2013M2), // 3. RIPE-MD/160
657                   REJECT,                   // 4. Reserved.
658                   REJECT,                   // 5. Reserved.
659                   REJECT,                   // 6. Reserved.
660                   REJECT,                   // 7. Reserved.
661                   ACCEPT,                   // 8. SHA256
662                   ACCEPT,                   // 9. SHA384
663                   ACCEPT,                   // 10. SHA512
664                   ACCEPT,                   // 11. SHA224
665                   ACCEPT,                   // 12. SHA3-256
666                   REJECT,                   // 13. Reserved.
667                   ACCEPT,                   // 14. SHA3-512
668               ]);
669
670a_cutoff_list!(SubpacketTagCutoffList, SubpacketTag, 40,
671               [
672                   REJECT,                 // 0. Reserved.
673                   REJECT,                 // 1. Reserved.
674                   ACCEPT,                 // 2. SignatureCreationTime.
675                   ACCEPT,                 // 3. SignatureExpirationTime.
676                   ACCEPT,                 // 4. ExportableCertification.
677                   ACCEPT,                 // 5. TrustSignature.
678                   ACCEPT,                 // 6. RegularExpression.
679                   // Note: Even though we don't explicitly honor the
680                   // Revocable flag, we don't support signature
681                   // revocations, hence it is safe to ACCEPT it.
682                   ACCEPT,                 // 7. Revocable.
683                   REJECT,                 // 8. Reserved.
684                   ACCEPT,                 // 9. KeyExpirationTime.
685                   REJECT,                 // 10. PlaceholderForBackwardCompatibility.
686                   ACCEPT,                 // 11. PreferredSymmetricAlgorithms.
687                   ACCEPT,                 // 12. RevocationKey.
688                   REJECT,                 // 13. Reserved.
689                   REJECT,                 // 14. Reserved.
690                   REJECT,                 // 15. Reserved.
691                   ACCEPT,                 // 16. Issuer.
692                   REJECT,                 // 17. Reserved.
693                   REJECT,                 // 18. Reserved.
694                   REJECT,                 // 19. Reserved.
695                   ACCEPT,                 // 20. NotationData.
696                   ACCEPT,                 // 21. PreferredHashAlgorithms.
697                   ACCEPT,                 // 22. PreferredCompressionAlgorithms.
698                   ACCEPT,                 // 23. KeyServerPreferences.
699                   ACCEPT,                 // 24. PreferredKeyServer.
700                   ACCEPT,                 // 25. PrimaryUserID.
701                   ACCEPT,                 // 26. PolicyURI.
702                   ACCEPT,                 // 27. KeyFlags.
703                   ACCEPT,                 // 28. SignersUserID.
704                   ACCEPT,                 // 29. ReasonForRevocation.
705                   ACCEPT,                 // 30. Features.
706                   REJECT,                 // 31. SignatureTarget.
707                   ACCEPT,                 // 32. EmbeddedSignature.
708                   ACCEPT,                 // 33. IssuerFingerprint.
709                   REJECT,                 // 34. Reserved (PreferredAEADAlgorithms).
710                   ACCEPT,                 // 35. IntendedRecipient.
711                   REJECT,                 // 36. Reserved.
712                   ACCEPT,                 // 37. ApprovedCertifications.
713                   REJECT,                 // 38. Reserved.
714                   ACCEPT,                 // 39. PreferredAEADCiphersuites.
715               ]);
716
717a_cutoff_list!(AsymmetricAlgorithmCutoffList, AsymmetricAlgorithm, 31,
718               [
719                   Some(Timestamp::Y2014M2), // 0. RSA1024.
720                   ACCEPT,                   // 1. RSA2048.
721                   ACCEPT,                   // 2. RSA3072.
722                   ACCEPT,                   // 3. RSA4096.
723                   Some(Timestamp::Y2014M2), // 4. ElGamal1024.
724                   Some(Timestamp::Y2025M2), // 5. ElGamal2048.
725                   Some(Timestamp::Y2025M2), // 6. ElGamal3072.
726                   Some(Timestamp::Y2025M2), // 7. ElGamal4096.
727                   Some(Timestamp::Y2014M2), // 8. DSA1024.
728                   Some(Timestamp::Y2030M2), // 9. DSA2048.
729                   Some(Timestamp::Y2030M2), // 10. DSA3072.
730                   Some(Timestamp::Y2030M2), // 11. DSA4096.
731                   ACCEPT,                   // 12. NistP256.
732                   ACCEPT,                   // 13. NistP384.
733                   ACCEPT,                   // 14. NistP521.
734                   ACCEPT,                   // 15. BrainpoolP256.
735                   ACCEPT,                   // 16. BrainpoolP384.
736                   ACCEPT,                   // 17. BrainpoolP512.
737                   ACCEPT,                   // 18. Cv25519.
738                   ACCEPT,                   // 19. X25519.
739                   ACCEPT,                   // 20. X448.
740                   ACCEPT,                   // 21. Ed25519.
741                   ACCEPT,                   // 22. Ed448.
742                   ACCEPT,                   // 23. EdDSA (i.e., Legacy Ed25519).
743                   ACCEPT,                   // 24. MLDSA65_Ed25519.
744                   ACCEPT,                   // 25. MLDSA87_Ed448.
745                   ACCEPT,                   // 26. SLHDSA128s.
746                   ACCEPT,                   // 27. SLHDSA128f.
747                   ACCEPT,                   // 28. SLHDSA256s.
748                   ACCEPT,                   // 29. MLKEM768_X25519.
749                   ACCEPT,                   // 30. MLKEM1024_X448.
750               ]);
751
752a_cutoff_list!(SymmetricAlgorithmCutoffList, SymmetricAlgorithm, 14,
753               [
754                   REJECT,                   // 0. Unencrypted.
755                   Some(Timestamp::Y2025M2), // 1. IDEA.
756                   Some(Timestamp::Y2017M2), // 2. TripleDES.
757                   Some(Timestamp::Y2025M2), // 3. CAST5.
758                   ACCEPT,                   // 4. Blowfish.
759                   REJECT,                   // 5. Reserved.
760                   REJECT,                   // 6. Reserved.
761                   ACCEPT,                   // 7. AES128.
762                   ACCEPT,                   // 8. AES192.
763                   ACCEPT,                   // 9. AES256.
764                   ACCEPT,                   // 10. Twofish.
765                   ACCEPT,                   // 11. Camellia128.
766                   ACCEPT,                   // 12. Camellia192.
767                   ACCEPT,                   // 13. Camellia256.
768               ]);
769
770a_cutoff_list!(AEADAlgorithmCutoffList, AEADAlgorithm, 4,
771               [
772                   REJECT,                 // 0. Reserved.
773                   ACCEPT,                 // 1. EAX.
774                   ACCEPT,                 // 2. OCB.
775                   ACCEPT,                 // 3. GCM.
776               ]);
777
778a_versioned_cutoff_list!(PacketTagCutoffList, Tag, 22,
779    [
780        REJECT,                   // 0. Reserved.
781        ACCEPT,                   // 1. PKESK.
782        ACCEPT,                   // 2. Signature.
783        ACCEPT,                   // 3. SKESK.
784        ACCEPT,                   // 4. OnePassSig.
785        ACCEPT,                   // 5. SecretKey.
786        ACCEPT,                   // 6. PublicKey.
787        ACCEPT,                   // 7. SecretSubkey.
788        ACCEPT,                   // 8. CompressedData.
789        Some(Timestamp::Y2004M2), // 9. SED.
790        ACCEPT,                   // 10. Marker.
791        ACCEPT,                   // 11. Literal.
792        ACCEPT,                   // 12. Trust.
793        ACCEPT,                   // 13. UserID.
794        ACCEPT,                   // 14. PublicSubkey.
795        REJECT,                   // 15. Not assigned.
796        REJECT,                   // 16. Not assigned.
797        ACCEPT,                   // 17. UserAttribute.
798        ACCEPT,                   // 18. SEIP.
799        ACCEPT,                   // 19. MDC.
800        REJECT,                   // 20. "v5" AED.
801        ACCEPT,                   // 21. Padding.
802    ],
803    // The versioned list overrides the unversioned list.  So we only
804    // need to tweak the above.
805    //
806    // Note: this list must be sorted and the tag and version must be unique!
807    2,
808    [
809        (Tag::Signature, 3, Some(Timestamp::Y2021M2)),
810        (Tag::Signature, 5, REJECT), // "v5" Signatures.
811    ]);
812
813// We need to convert a `SystemTime` to a `Timestamp` in
814// `StandardPolicy::reject_hash_at`.  Unfortunately, a `SystemTime`
815// can represent a larger range of time than a `Timestamp` can.  Since
816// the times passed to this function are cutoff points, and we only
817// compare them to OpenPGP timestamps, any `SystemTime` that is prior
818// to the Unix Epoch is equivalent to the Unix Epoch: it will reject
819// all timestamps.  Similarly, any `SystemTime` that is later than the
820// latest time representable by a `Timestamp` is equivalent to
821// accepting all time stamps, which is equivalent to passing None.
822fn system_time_cutoff_to_timestamp(t: SystemTime) -> Option<Timestamp> {
823    let t = t
824        .duration_since(SystemTime::UNIX_EPOCH)
825        // An error can only occur if the SystemTime is less than the
826        // reference time (SystemTime::UNIX_EPOCH).  Map that to
827        // SystemTime::UNIX_EPOCH, as above.
828        .unwrap_or_else(|_| Duration::new(0, 0));
829    let t = t.as_secs();
830    if t > u32::MAX as u64 {
831        // Map to None, as above.
832        None
833    } else {
834        Some((t as u32).into())
835    }
836}
837
838impl<'a> StandardPolicy<'a> {
839    /// Instantiates a new `StandardPolicy` with the default parameters.
840    pub const fn new() -> Self {
841        const EMPTY_LIST: &[&str] = &[];
842        Self {
843            time: None,
844            collision_resistant_hash_algos:
845                CollisionResistantHashCutoffList::Default(),
846            second_pre_image_resistant_hash_algos:
847                SecondPreImageResistantHashCutoffList::Default(),
848            // There are 365.2425 days in a year.  Use a reasonable
849            // approximation.
850            hash_revocation_tolerance:
851                types::Duration::seconds((7 * 365 + 2) * 24 * 60 * 60),
852            critical_subpackets: SubpacketTagCutoffList::Default(),
853            good_critical_notations: EMPTY_LIST,
854            asymmetric_algos: AsymmetricAlgorithmCutoffList::Default(),
855            symmetric_algos: SymmetricAlgorithmCutoffList::Default(),
856            aead_algos: AEADAlgorithmCutoffList::Default(),
857            packet_tags: PacketTagCutoffList::Default(),
858        }
859    }
860
861    /// Instantiates a new `StandardPolicy` with parameters
862    /// appropriate for `time`.
863    ///
864    /// `time` is a meta-parameter that selects a security profile
865    /// that is appropriate for the given point in time.  When
866    /// evaluating an object, the reference time should be set to the
867    /// time that the object was stored to non-tamperable storage.
868    /// Since most applications don't record when they received an
869    /// object, they should conservatively use the current time.
870    ///
871    /// Note that the reference time is a security parameter and is
872    /// different from the time that the object was allegedly created.
873    /// Consider evaluating a signature whose `Signature Creation
874    /// Time` subpacket indicates that it was created in 2007.  Since
875    /// the subpacket is under the control of the sender, setting the
876    /// reference time according to the subpacket means that the
877    /// sender chooses the security profile.  If the sender were an
878    /// attacker, she could have forged this to take advantage of
879    /// security weaknesses found since 2007.  This is why the
880    /// reference time must be set---at the earliest---to the time
881    /// that the message was stored to non-tamperable storage.  When
882    /// that is not available, the current time should be used.
883    pub fn at<T>(time: T) -> Self
884        where T: Into<SystemTime>,
885    {
886        let time = time.into();
887        let mut p = Self::new();
888        p.time = Some(system_time_cutoff_to_timestamp(time)
889                          // Map "ACCEPT" to the end of time (None
890                          // here means the current time).
891                          .unwrap_or(Timestamp::MAX));
892        p
893    }
894
895    /// Returns the policy's reference time.
896    ///
897    /// The current time is None.
898    ///
899    /// See [`StandardPolicy::at`] for details.
900    ///
901    /// [`StandardPolicy::at`]: StandardPolicy::at()
902    pub fn time(&self) -> Option<SystemTime> {
903        self.time.map(Into::into)
904    }
905
906    /// Always considers `h` to be secure.
907    ///
908    /// A cryptographic hash algorithm normally has three security
909    /// properties:
910    ///
911    ///   - Pre-image resistance,
912    ///   - Second pre-image resistance, and
913    ///   - Collision resistance.
914    ///
915    /// A hash algorithm should only be unconditionally accepted if it
916    /// has all three of these properties.  See the documentation for
917    /// [`HashAlgoSecurity`] for more details.
918    pub fn accept_hash(&mut self, h: HashAlgorithm) {
919        self.accept_hash_property(h, HashAlgoSecurity::CollisionResistance);
920        self.accept_hash_property(h, HashAlgoSecurity::SecondPreImageResistance);
921    }
922
923    /// Considers hash algorithm `h` to be secure for the specified
924    /// security property `sec`.
925    ///
926    /// For instance, an application may choose to allow an algorithm
927    /// like SHA-1 in contexts like User ID binding signatures where
928    /// only [second preimage
929    /// resistance][`HashAlgoSecurity::SecondPreImageResistance`] is
930    /// required but not in contexts like signatures over data where
931    /// [collision
932    /// resistance][`HashAlgoSecurity::CollisionResistance`] is also
933    /// required. Whereas SHA-1's collision resistance is
934    /// [definitively broken](https://shattered.io/), depending on the
935    /// application's threat model, it may be acceptable to continue
936    /// to accept SHA-1 in these specific contexts.
937    pub fn accept_hash_property(&mut self, h: HashAlgorithm, sec: HashAlgoSecurity)
938    {
939        self.reject_hash_property_at(h, sec, None);
940    }
941
942    /// Considers `h` to be insecure in all security contexts.
943    ///
944    /// A cryptographic hash algorithm normally has three security
945    /// properties:
946    ///
947    ///   - Pre-image resistance,
948    ///   - Second pre-image resistance, and
949    ///   - Collision resistance.
950    ///
951    /// This method causes the hash algorithm to be considered unsafe
952    /// in all security contexts.
953    ///
954    /// See the documentation for [`HashAlgoSecurity`] for more
955    /// details.
956    ///
957    ///
958    /// To express a more nuanced policy, use
959    /// [`StandardPolicy::reject_hash_at`] or
960    /// [`StandardPolicy::reject_hash_property_at`].
961    ///
962    ///   [`StandardPolicy::reject_hash_at`]: StandardPolicy::reject_hash_at()
963    ///   [`StandardPolicy::reject_hash_property_at`]: StandardPolicy::reject_hash_property_at()
964    pub fn reject_hash(&mut self, h: HashAlgorithm) {
965        self.collision_resistant_hash_algos.set(h, REJECT);
966        self.second_pre_image_resistant_hash_algos.set(h, REJECT);
967    }
968
969    /// Considers all hash algorithms to be insecure.
970    ///
971    /// Causes all hash algorithms to be considered insecure in all
972    /// security contexts.
973    ///
974    /// This is useful when using a good list to determine what
975    /// algorithms are allowed.
976    pub fn reject_all_hashes(&mut self) {
977        self.collision_resistant_hash_algos.reject_all();
978        self.second_pre_image_resistant_hash_algos.reject_all();
979    }
980
981    /// Considers `h` to be insecure in all security contexts starting
982    /// at time `t`.
983    ///
984    /// A cryptographic hash algorithm normally has three security
985    /// properties:
986    ///
987    ///   - Pre-image resistance,
988    ///   - Second pre-image resistance, and
989    ///   - Collision resistance.
990    ///
991    /// This method causes the hash algorithm to be considered unsafe
992    /// in all security contexts starting at time `t`.
993    ///
994    /// See the documentation for [`HashAlgoSecurity`] for more
995    /// details.
996    ///
997    ///
998    /// To express a more nuanced policy, use
999    /// [`StandardPolicy::reject_hash_property_at`].
1000    ///
1001    ///   [`StandardPolicy::reject_hash_property_at`]: StandardPolicy::reject_hash_property_at()
1002    pub fn reject_hash_at<T>(&mut self, h: HashAlgorithm, t: T)
1003        where T: Into<Option<SystemTime>>,
1004    {
1005        let t = t.into().and_then(system_time_cutoff_to_timestamp);
1006        self.collision_resistant_hash_algos.set(h, t);
1007        self.second_pre_image_resistant_hash_algos.set(h, t);
1008    }
1009
1010    /// Considers `h` to be insecure starting at `t` for the specified
1011    /// security property.
1012    ///
1013    /// A hash algorithm is considered secure if it has all of the
1014    /// following security properties:
1015    ///
1016    ///   - Pre-image resistance,
1017    ///   - Second pre-image resistance, and
1018    ///   - Collision resistance.
1019    ///
1020    /// Some contexts only require a subset of these security
1021    /// properties.  Specifically, if an attacker is unable to
1022    /// influence the data that a user signs, then the hash algorithm
1023    /// only needs second pre-image resistance; it doesn't need
1024    /// collision resistance.  See the documentation for
1025    /// [`HashAlgoSecurity`] for more details.
1026    ///
1027    ///
1028    /// This method makes it possible to specify different policies
1029    /// depending on the security requirements.
1030    ///
1031    /// A cutoff of `None` means that there is no cutoff and the
1032    /// algorithm has no known vulnerabilities for the specified
1033    /// security policy.
1034    ///
1035    /// As a rule of thumb, collision resistance is easier to attack
1036    /// than second pre-image resistance.  And in practice there are
1037    /// practical attacks against several widely-used hash algorithms'
1038    /// collision resistance, but only theoretical attacks against
1039    /// their second pre-image resistance.  Nevertheless, once one
1040    /// property of a hash has been compromised, we want to deprecate
1041    /// its use as soon as it is feasible.  Unfortunately, because
1042    /// OpenPGP certificates are long-lived, this can take years.
1043    ///
1044    /// Given this, we start rejecting [MD5] in cases where collision
1045    /// resistance is required in 1997 and completely reject it
1046    /// starting in 2004:
1047    ///
1048    /// >  In 1996, Dobbertin announced a collision of the
1049    /// >  compression function of MD5 (Dobbertin, 1996). While this
1050    /// >  was not an attack on the full MD5 hash function, it was
1051    /// >  close enough for cryptographers to recommend switching to
1052    /// >  a replacement, such as SHA-1 or RIPEMD-160.
1053    /// >
1054    /// >  MD5CRK ended shortly after 17 August 2004, when collisions
1055    /// >  for the full MD5 were announced by Xiaoyun Wang, Dengguo
1056    /// >  Feng, Xuejia Lai, and Hongbo Yu. Their analytical attack
1057    /// >  was reported to take only one hour on an IBM p690 cluster.
1058    /// >
1059    /// > (Accessed Feb. 2020.)
1060    ///
1061    ///   [MD5]: https://en.wikipedia.org/wiki/MD5
1062    ///
1063    /// And we start rejecting [SHA-1] in cases where collision
1064    /// resistance is required in 2013, and completely reject it in
1065    /// 2023:
1066    ///
1067    /// > Since 2005 SHA-1 has not been considered secure against
1068    /// > well-funded opponents, as of 2010 many organizations have
1069    /// > recommended its replacement. NIST formally deprecated use
1070    /// > of SHA-1 in 2011 and disallowed its use for digital
1071    /// > signatures in 2013. As of 2020, attacks against SHA-1 are
1072    /// > as practical as against MD5; as such, it is recommended to
1073    /// > remove SHA-1 from products as soon as possible and use
1074    /// > instead SHA-256 or SHA-3. Replacing SHA-1 is urgent where
1075    /// > it's used for signatures.
1076    /// >
1077    /// > (Accessed Feb. 2020.)
1078    ///
1079    ///   [SHA-1]: https://en.wikipedia.org/wiki/SHA-1
1080    ///
1081    /// There are two main reasons why we have decided to accept SHA-1
1082    /// for so long.  First, as of the end of 2020, there are still a
1083    /// large number of [certificates that rely on SHA-1].  Second,
1084    /// Sequoia uses a variant of SHA-1 called [SHA1CD], which is able
1085    /// to detect and *mitigate* the known attacks on SHA-1's
1086    /// collision resistance.
1087    ///
1088    ///   [certificates that rely on SHA-1]: https://gitlab.com/sequoia-pgp/sequoia/-/issues/595
1089    ///   [SHA1CD]: https://github.com/cr-marcstevens/sha1collisiondetection
1090    ///
1091    /// Since RIPE-MD is structured similarly to SHA-1, we
1092    /// conservatively consider it to be broken as well.  But, because
1093    /// it is not widely used in the OpenPGP ecosystem, we don't make
1094    /// provisions for it.
1095    ///
1096    /// Note: if a context indicates that it requires collision
1097    /// resistance, then it requires both collision resistance and
1098    /// second pre-image resistance, and both policies must indicate
1099    /// that the hash algorithm can be safely used at the specified
1100    /// time.
1101    pub fn reject_hash_property_at<T>(&mut self, h: HashAlgorithm,
1102                                      sec: HashAlgoSecurity, t: T)
1103        where T: Into<Option<SystemTime>>,
1104    {
1105        let t = t.into().and_then(system_time_cutoff_to_timestamp);
1106        match sec {
1107            HashAlgoSecurity::CollisionResistance =>
1108                self.collision_resistant_hash_algos.set(h, t),
1109            HashAlgoSecurity::SecondPreImageResistance =>
1110                self.second_pre_image_resistant_hash_algos.set(h, t),
1111        }
1112    }
1113
1114    /// Returns the cutoff time for the specified hash algorithm and
1115    /// security policy.
1116    pub fn hash_cutoff(&self, h: HashAlgorithm, sec: HashAlgoSecurity)
1117        -> Option<SystemTime>
1118    {
1119        match sec {
1120            HashAlgoSecurity::CollisionResistance =>
1121                self.collision_resistant_hash_algos.cutoff(h),
1122            HashAlgoSecurity::SecondPreImageResistance =>
1123                self.second_pre_image_resistant_hash_algos.cutoff(h),
1124        }.map(|t| t.into())
1125    }
1126
1127    /// Sets the amount of time to continue to accept revocation
1128    /// certificates after a hash algorithm should be rejected.
1129    ///
1130    /// Using [`StandardPolicy::reject_hash_at`], it is possible to
1131    /// indicate when a hash algorithm's security has been
1132    /// compromised, and, as such, should no longer be accepted.
1133    ///
1134    ///   [`StandardPolicy::reject_hash_at`]: StandardPolicy::reject_hash_at()
1135    ///
1136    /// Applying this policy to revocation certificates can have some
1137    /// unfortunate side effects.  In particular, if a certificate has
1138    /// been revoked using a revocation certificate that relies on a
1139    /// broken hash algorithm, but the most recent self signature uses
1140    /// a strong acceptable hash algorithm, then rejecting the
1141    /// revocation certificate would mean considering the certificate
1142    /// to not be revoked!  This would be a catastrophe if the secret
1143    /// key material were compromised.
1144    ///
1145    /// Unfortunately, this happens in practice.  A common example
1146    /// appears to be a certificate that has been updated many times,
1147    /// and is then revoked using a revocation certificate that was
1148    /// generated when the certificate was generated.
1149    ///
1150    /// Since the consequences of allowing an invalid revocation
1151    /// certificate are significantly less severe (a denial of
1152    /// service) than ignoring a valid revocation certificate
1153    /// (compromised confidentiality, integrity, and authentication),
1154    /// this option makes it possible to accept revocations using weak
1155    /// hash algorithms longer than other types of signatures.
1156    ///
1157    /// By default, the standard policy accepts revocation
1158    /// certificates seven years after the hash they are using was
1159    /// initially compromised.
1160    pub fn hash_revocation_tolerance<D>(&mut self, d: D)
1161        where D: Into<types::Duration>
1162    {
1163        self.hash_revocation_tolerance = d.into();
1164    }
1165
1166    /// Sets the amount of time to continue to accept revocation
1167    /// certificates after a hash algorithm should be rejected.
1168    ///
1169    /// See [`StandardPolicy::hash_revocation_tolerance`] for details.
1170    ///
1171    ///   [`StandardPolicy::hash_revocation_tolerance`]: StandardPolicy::hash_revocation_tolerance()
1172    pub fn get_hash_revocation_tolerance(&self) -> types::Duration {
1173        self.hash_revocation_tolerance
1174    }
1175
1176    /// Always considers `s` to be secure.
1177    pub fn accept_critical_subpacket(&mut self, s: SubpacketTag) {
1178        self.critical_subpackets.set(s, ACCEPT);
1179    }
1180
1181    /// Always considers `s` to be insecure.
1182    pub fn reject_critical_subpacket(&mut self, s: SubpacketTag) {
1183        self.critical_subpackets.set(s, REJECT);
1184    }
1185
1186    /// Considers all critical subpackets to be insecure.
1187    ///
1188    /// This is useful when using a good list to determine what
1189    /// critical subpackets are allowed.
1190    pub fn reject_all_critical_subpackets(&mut self) {
1191        self.critical_subpackets.reject_all();
1192    }
1193
1194    /// Considers `s` to be insecure starting at `cutoff`.
1195    ///
1196    /// A cutoff of `None` means that there is no cutoff and the
1197    /// subpacket has no known vulnerabilities.
1198    ///
1199    /// By default, we accept all critical subpackets that Sequoia
1200    /// understands and honors.
1201    pub fn reject_critical_subpacket_at<C>(&mut self, s: SubpacketTag,
1202                                       cutoff: C)
1203        where C: Into<Option<SystemTime>>,
1204    {
1205        self.critical_subpackets.set(
1206            s,
1207            cutoff.into().and_then(system_time_cutoff_to_timestamp));
1208    }
1209
1210    /// Returns the cutoff times for the specified subpacket tag.
1211    pub fn critical_subpacket_cutoff(&self, s: SubpacketTag)
1212                                 -> Option<SystemTime> {
1213        self.critical_subpackets.cutoff(s).map(|t| t.into())
1214    }
1215
1216    /// Sets the list of accepted critical notations.
1217    ///
1218    /// By default, we reject all critical notations.
1219    pub fn good_critical_notations(&mut self, good_list: &'a [&'a str]) {
1220        self.good_critical_notations = good_list;
1221    }
1222
1223    /// Always considers `s` to be secure.
1224    pub fn accept_asymmetric_algo(&mut self, a: AsymmetricAlgorithm) {
1225        self.asymmetric_algos.set(a, ACCEPT);
1226    }
1227
1228    /// Always considers `s` to be insecure.
1229    pub fn reject_asymmetric_algo(&mut self, a: AsymmetricAlgorithm) {
1230        self.asymmetric_algos.set(a, REJECT);
1231    }
1232
1233    /// Considers all asymmetric algorithms to be insecure.
1234    ///
1235    /// This is useful when using a good list to determine what
1236    /// algorithms are allowed.
1237    pub fn reject_all_asymmetric_algos(&mut self) {
1238        self.asymmetric_algos.reject_all();
1239    }
1240
1241    /// Considers `a` to be insecure starting at `cutoff`.
1242    ///
1243    /// A cutoff of `None` means that there is no cutoff and the
1244    /// algorithm has no known vulnerabilities.
1245    ///
1246    /// By default, we reject the use of asymmetric key sizes lower
1247    /// than 2048 bits starting in 2014 following [NIST Special
1248    /// Publication 800-131A].
1249    ///
1250    ///   [NIST Special Publication 800-131A]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf
1251    pub fn reject_asymmetric_algo_at<C>(&mut self, a: AsymmetricAlgorithm,
1252                                       cutoff: C)
1253        where C: Into<Option<SystemTime>>,
1254    {
1255        self.asymmetric_algos.set(
1256            a,
1257            cutoff.into().and_then(system_time_cutoff_to_timestamp));
1258    }
1259
1260    /// Returns the cutoff times for the specified hash algorithm.
1261    pub fn asymmetric_algo_cutoff(&self, a: AsymmetricAlgorithm)
1262                                 -> Option<SystemTime> {
1263        self.asymmetric_algos.cutoff(a).map(|t| t.into())
1264    }
1265
1266    /// Always considers `s` to be secure.
1267    pub fn accept_symmetric_algo(&mut self, s: SymmetricAlgorithm) {
1268        self.symmetric_algos.set(s, ACCEPT);
1269    }
1270
1271    /// Always considers `s` to be insecure.
1272    pub fn reject_symmetric_algo(&mut self, s: SymmetricAlgorithm) {
1273        self.symmetric_algos.set(s, REJECT);
1274    }
1275
1276    /// Considers all symmetric algorithms to be insecure.
1277    ///
1278    /// This is useful when using a good list to determine what
1279    /// algorithms are allowed.
1280    pub fn reject_all_symmetric_algos(&mut self) {
1281        self.symmetric_algos.reject_all();
1282    }
1283
1284    /// Considers `s` to be insecure starting at `cutoff`.
1285    ///
1286    /// A cutoff of `None` means that there is no cutoff and the
1287    /// algorithm has no known vulnerabilities.
1288    ///
1289    /// By default, we reject the use of TripleDES (3DES) starting in
1290    /// the year 2017.  While 3DES is still a ["MUST implement"]
1291    /// algorithm in RFC4880, released in 2007, there are plenty of
1292    /// other symmetric algorithms defined in RFC4880, and it says
1293    /// AES-128 SHOULD be implemented.  Support for other algorithms
1294    /// in OpenPGP implementations is [excellent].  We chose 2017 as
1295    /// the cutoff year because [NIST deprecated 3DES] that year.
1296    ///
1297    ///   ["MUST implement"]: https://www.rfc-editor.org/rfc/rfc9580.html#section-9.3
1298    ///   [excellent]: https://tests.sequoia-pgp.org/#Symmetric_Encryption_Algorithm_support
1299    ///   [NIST deprecated 3DES]: https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
1300    pub fn reject_symmetric_algo_at<C>(&mut self, s: SymmetricAlgorithm,
1301                                       cutoff: C)
1302        where C: Into<Option<SystemTime>>,
1303    {
1304        self.symmetric_algos.set(
1305            s,
1306            cutoff.into().and_then(system_time_cutoff_to_timestamp));
1307    }
1308
1309    /// Returns the cutoff times for the specified hash algorithm.
1310    pub fn symmetric_algo_cutoff(&self, s: SymmetricAlgorithm)
1311                                 -> Option<SystemTime> {
1312        self.symmetric_algos.cutoff(s).map(|t| t.into())
1313    }
1314
1315    /// Always considers `s` to be secure.
1316    ///
1317    /// This feature is [experimental](super#experimental-features).
1318    pub fn accept_aead_algo(&mut self, a: AEADAlgorithm) {
1319        self.aead_algos.set(a, ACCEPT);
1320    }
1321
1322    /// Always considers `s` to be insecure.
1323    ///
1324    /// This feature is [experimental](super#experimental-features).
1325    pub fn reject_aead_algo(&mut self, a: AEADAlgorithm) {
1326        self.aead_algos.set(a, REJECT);
1327    }
1328
1329    /// Considers all AEAD algorithms to be insecure.
1330    ///
1331    /// This is useful when using a good list to determine what
1332    /// algorithms are allowed.
1333    pub fn reject_all_aead_algos(&mut self) {
1334        self.aead_algos.reject_all();
1335    }
1336
1337    /// Considers `a` to be insecure starting at `cutoff`.
1338    ///
1339    /// A cutoff of `None` means that there is no cutoff and the
1340    /// algorithm has no known vulnerabilities.
1341    ///
1342    /// By default, we accept all AEAD modes.
1343    ///
1344    /// This feature is [experimental](super#experimental-features).
1345    pub fn reject_aead_algo_at<C>(&mut self, a: AEADAlgorithm,
1346                                       cutoff: C)
1347        where C: Into<Option<SystemTime>>,
1348    {
1349        self.aead_algos.set(
1350            a,
1351            cutoff.into().and_then(system_time_cutoff_to_timestamp));
1352    }
1353
1354    /// Returns the cutoff times for the specified hash algorithm.
1355    ///
1356    /// This feature is [experimental](super#experimental-features).
1357    pub fn aead_algo_cutoff(&self, a: AEADAlgorithm)
1358                                 -> Option<SystemTime> {
1359        self.aead_algos.cutoff(a).map(|t| t.into())
1360    }
1361
1362    /// Always accept the specified version of the packet.
1363    ///
1364    /// If a packet does not have a version field, then its version is
1365    /// `0`.
1366    pub fn accept_packet_tag_version(&mut self, tag: Tag, version: u8) {
1367        self.packet_tags.set_versioned(tag, version, ACCEPT);
1368    }
1369
1370    /// Always accept packets with the given tag independent of their
1371    /// version.
1372    ///
1373    /// If you previously set a cutoff for a specific version of a
1374    /// packet, this overrides that.
1375    pub fn accept_packet_tag(&mut self, tag: Tag) {
1376        self.packet_tags.set_unversioned(tag, ACCEPT);
1377    }
1378
1379    /// Always reject the specified version of the packet.
1380    ///
1381    /// If a packet does not have a version field, then its version is
1382    /// `0`.
1383    pub fn reject_packet_tag_version(&mut self, tag: Tag, version: u8) {
1384        self.packet_tags.set_versioned(tag, version, REJECT);
1385    }
1386
1387    /// Always reject packets with the given tag.
1388    pub fn reject_packet_tag(&mut self, tag: Tag) {
1389        self.packet_tags.set_unversioned(tag, REJECT);
1390    }
1391
1392    /// Considers all packets to be insecure.
1393    ///
1394    /// This is useful when using a good list to determine what
1395    /// packets are allowed.
1396    pub fn reject_all_packet_tags(&mut self) {
1397        self.packet_tags.reject_all();
1398    }
1399
1400    /// Start rejecting the specified version of packets with the
1401    /// given tag at `t`.
1402    ///
1403    /// A cutoff of `None` means that there is no cutoff and the
1404    /// packet has no known vulnerabilities.
1405    ///
1406    /// By default, we consider the *Symmetrically Encrypted Data
1407    /// Packet* (SED) insecure in messages created in the year 2004 or
1408    /// later.  The rationale here is that *Symmetrically Encrypted
1409    /// Integrity Protected Data Packet* (SEIP) can be downgraded to
1410    /// SED packets, enabling attacks exploiting the malleability of
1411    /// the CFB stream (see [EFAIL]).
1412    ///
1413    ///   [EFAIL]: https://en.wikipedia.org/wiki/EFAIL
1414    ///
1415    /// We chose 2004 as a cutoff-date because [Debian 3.0] (Woody),
1416    /// released on 2002-07-19, was the first release of Debian to
1417    /// ship a version of GnuPG that emitted SEIP packets by default.
1418    /// The first version that emitted SEIP packets was [GnuPG 1.0.3],
1419    /// released on 2000-09-18.  Mid 2002 plus an 18 months grace
1420    /// period of people still using older versions is 2004.
1421    ///
1422    ///   [Debian 3.0]: https://www.debian.org/News/2002/20020719
1423    ///   [GnuPG 1.0.3]: https://lists.gnupg.org/pipermail/gnupg-announce/2000q3/000075.html
1424    pub fn reject_packet_tag_version_at<C>(&mut self, tag: Tag, version: u8,
1425                                           cutoff: C)
1426        where C: Into<Option<SystemTime>>,
1427    {
1428        self.packet_tags.set_versioned(
1429            tag, version,
1430            cutoff.into().and_then(system_time_cutoff_to_timestamp));
1431    }
1432
1433    /// Start rejecting packets with the given tag at `t`.
1434    ///
1435    /// See the documentation for
1436    /// [`StandardPolicy::reject_packet_tag_version_at`].
1437    pub fn reject_packet_tag_at<C>(&mut self, tag: Tag, cutoff: C)
1438        where C: Into<Option<SystemTime>>,
1439    {
1440        self.packet_tags.set_unversioned(
1441            tag,
1442            cutoff.into().and_then(system_time_cutoff_to_timestamp));
1443    }
1444
1445    /// Returns the cutoff for the specified version of the specified
1446    /// packet tag.
1447    ///
1448    /// This first considers the versioned cutoff list.  If there is
1449    /// no entry in the versioned list, it fallsback to the
1450    /// unversioned cutoff list.  If there is also no entry there,
1451    /// then it falls back to the default.
1452    pub fn packet_tag_version_cutoff(&self, tag: Tag, version: u8)
1453        -> Option<SystemTime>
1454    {
1455        self.packet_tags.cutoff(tag, version).map(|t| t.into())
1456    }
1457}
1458
1459impl<'a> Policy for StandardPolicy<'a> {
1460    fn signature(&self, sig: &Signature, sec: HashAlgoSecurity) -> Result<()> {
1461        let time = self.time.unwrap_or_else(Timestamp::now);
1462
1463        let rev = matches!(sig.typ(), SignatureType::KeyRevocation
1464                | SignatureType::SubkeyRevocation
1465                | SignatureType::CertificationRevocation);
1466
1467        // Note: collision resistance requires 2nd pre-image resistance.
1468        if sec == HashAlgoSecurity::CollisionResistance {
1469            if rev {
1470                self
1471                    .collision_resistant_hash_algos
1472                    .check(sig.hash_algo(), time,
1473                           Some(self.hash_revocation_tolerance))
1474                    .with_context(|| format!(
1475                        "Policy rejected revocation signature ({}) requiring \
1476                         collision resistance", sig.typ()))?
1477            } else {
1478                self
1479                    .collision_resistant_hash_algos
1480                    .check(sig.hash_algo(), time, None)
1481                    .with_context(|| format!(
1482                        "Policy rejected non-revocation signature ({}) requiring \
1483                         collision resistance", sig.typ()))?
1484            }
1485        }
1486
1487        if rev {
1488            self
1489                .second_pre_image_resistant_hash_algos
1490                .check(sig.hash_algo(), time,
1491                       Some(self.hash_revocation_tolerance))
1492                .with_context(|| format!(
1493                    "Policy rejected revocation signature ({}) requiring \
1494                     second pre-image resistance", sig.typ()))?
1495        } else {
1496            self
1497                .second_pre_image_resistant_hash_algos
1498                .check(sig.hash_algo(), time, None)
1499                .with_context(|| format!(
1500                    "Policy rejected non-revocation signature ({}) requiring \
1501                     second pre-image resistance", sig.typ()))?
1502        }
1503
1504        for csp in sig.hashed_area().iter().filter(|sp| sp.critical()) {
1505            self.critical_subpackets.check(csp.tag(), time, None)
1506                .context("Policy rejected critical signature subpacket")?;
1507            if let SubpacketValue::NotationData(n) = csp.value() {
1508                if ! self.good_critical_notations.contains(&n.name()) {
1509                    return Err(anyhow::Error::from(
1510                        Error::PolicyViolation(
1511                            format!("Critical notation {:?}",
1512                                    n.name()), None))
1513                               .context("Policy rejected critical notation"));
1514                }
1515            }
1516        }
1517
1518        Ok(())
1519    }
1520
1521    fn key(&self, ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
1522        -> Result<()>
1523    {
1524        use crate::types::PublicKeyAlgorithm::{self, *};
1525        use crate::crypto::mpi::PublicKey;
1526
1527        #[allow(deprecated)]
1528        let a = match (ka.key().pk_algo(), ka.key().mpis().bits()) {
1529            // RSA.
1530            (RSAEncryptSign, Some(b))
1531                | (RSAEncrypt, Some(b))
1532                | (RSASign, Some(b))
1533                if b < 2048 => AsymmetricAlgorithm::RSA1024,
1534            (RSAEncryptSign, Some(b))
1535                | (RSAEncrypt, Some(b))
1536                | (RSASign, Some(b))
1537                if b < 3072 => AsymmetricAlgorithm::RSA2048,
1538            (RSAEncryptSign, Some(b))
1539                | (RSAEncrypt, Some(b))
1540                | (RSASign, Some(b))
1541                if b < 4096 => AsymmetricAlgorithm::RSA3072,
1542            (RSAEncryptSign, Some(_))
1543                | (RSAEncrypt, Some(_))
1544                | (RSASign, Some(_))
1545                => AsymmetricAlgorithm::RSA4096,
1546            (RSAEncryptSign, None)
1547                | (RSAEncrypt, None)
1548                | (RSASign, None) => unreachable!(),
1549
1550            // ElGamal.
1551            (ElGamalEncryptSign, Some(b))
1552                | (ElGamalEncrypt, Some(b))
1553                if b < 2048 => AsymmetricAlgorithm::ElGamal1024,
1554            (ElGamalEncryptSign, Some(b))
1555                | (ElGamalEncrypt, Some(b))
1556                if b < 3072 => AsymmetricAlgorithm::ElGamal2048,
1557            (ElGamalEncryptSign, Some(b))
1558                | (ElGamalEncrypt, Some(b))
1559                if b < 4096 => AsymmetricAlgorithm::ElGamal3072,
1560            (ElGamalEncryptSign, Some(_))
1561                | (ElGamalEncrypt, Some(_))
1562                => AsymmetricAlgorithm::ElGamal4096,
1563            (ElGamalEncryptSign, None)
1564                | (ElGamalEncrypt, None) => unreachable!(),
1565
1566            // DSA.
1567            (DSA, Some(b))
1568                if b < 2048 => AsymmetricAlgorithm::DSA1024,
1569            (DSA, Some(b))
1570                if b < 3072 => AsymmetricAlgorithm::DSA2048,
1571            (DSA, Some(b))
1572                if b < 4096 => AsymmetricAlgorithm::DSA3072,
1573            (DSA, Some(_))
1574                => AsymmetricAlgorithm::DSA4096,
1575            (DSA, None) => unreachable!(),
1576
1577            // ECC.
1578            (ECDH, _) | (ECDSA, _) | (EdDSA, _) => {
1579                let curve = match ka.key().mpis() {
1580                    PublicKey::EdDSA { curve, .. } => curve,
1581                    PublicKey::ECDSA { curve, .. } => curve,
1582                    PublicKey::ECDH { curve, .. } => curve,
1583                    _ => unreachable!(),
1584                };
1585                use crate::types::Curve;
1586                match curve {
1587                    Curve::NistP256 => AsymmetricAlgorithm::NistP256,
1588                    Curve::NistP384 => AsymmetricAlgorithm::NistP384,
1589                    Curve::NistP521 => AsymmetricAlgorithm::NistP521,
1590                    Curve::BrainpoolP256 => AsymmetricAlgorithm::BrainpoolP256,
1591                    Curve::BrainpoolP384 => AsymmetricAlgorithm::BrainpoolP384,
1592                    Curve::BrainpoolP512 => AsymmetricAlgorithm::BrainpoolP512,
1593                    Curve::Ed25519 => AsymmetricAlgorithm::EdDSA,
1594                    Curve::Cv25519 => AsymmetricAlgorithm::Cv25519,
1595                    Curve::Unknown(_) => AsymmetricAlgorithm::Unknown,
1596                }
1597            },
1598
1599            (PublicKeyAlgorithm::X25519, _) => AsymmetricAlgorithm::X25519,
1600            (PublicKeyAlgorithm::X448, _) => AsymmetricAlgorithm::X448,
1601            (PublicKeyAlgorithm::Ed25519, _) => AsymmetricAlgorithm::Ed25519,
1602            (PublicKeyAlgorithm::Ed448, _) => AsymmetricAlgorithm::Ed448,
1603
1604            (PublicKeyAlgorithm::MLDSA65_Ed25519, _) =>
1605                AsymmetricAlgorithm::MLDSA65_Ed25519,
1606            (PublicKeyAlgorithm::MLDSA87_Ed448, _) =>
1607                AsymmetricAlgorithm::MLDSA87_Ed448,
1608
1609            (PublicKeyAlgorithm::SLHDSA128s, _) =>
1610                AsymmetricAlgorithm::SLHDSA128s,
1611            (PublicKeyAlgorithm::SLHDSA128f, _) =>
1612                AsymmetricAlgorithm::SLHDSA128f,
1613            (PublicKeyAlgorithm::SLHDSA256s, _) =>
1614                AsymmetricAlgorithm::SLHDSA256s,
1615
1616            (PublicKeyAlgorithm::MLKEM768_X25519, _) =>
1617                AsymmetricAlgorithm::MLKEM768_X25519,
1618            (PublicKeyAlgorithm::MLKEM1024_X448, _) =>
1619                AsymmetricAlgorithm::MLKEM1024_X448,
1620
1621            (PublicKeyAlgorithm::Private(_), _)
1622                | (PublicKeyAlgorithm::Unknown(_), _)
1623                => AsymmetricAlgorithm::Unknown,
1624        };
1625
1626        let time = self.time.unwrap_or_else(Timestamp::now);
1627        self.asymmetric_algos.check(a, time, None)
1628            .context("Policy rejected asymmetric algorithm")?;
1629
1630        // Check ECDH KDF and KEK parameters.
1631        if let PublicKey::ECDH { hash, sym, .. } = ka.key().mpis() {
1632            self.symmetric_algorithm(*sym)
1633                .context("Policy rejected ECDH \
1634                          key encapsulation algorithm")?;
1635
1636            // RFC6637 says:
1637            //
1638            // > Refer to Section 13 for the details regarding the
1639            // > choice of the KEK algorithm, which SHOULD be one of
1640            // > three AES algorithms.
1641            //
1642            // Furthermore, GnuPG rejects anything other than AES.
1643            // I checked the SKS dump, and there are no keys out
1644            // there that use a different KEK algorithm.
1645            match sym {
1646                SymmetricAlgorithm::AES128
1647                    | SymmetricAlgorithm::AES192
1648                    | SymmetricAlgorithm::AES256
1649                    => (), // Good.
1650                _ =>
1651                    return Err(anyhow::Error::from(
1652                        Error::PolicyViolation(sym.to_string(), None))
1653                               .context("Policy rejected ECDH \
1654                                         key encapsulation algorithm")),
1655            }
1656
1657            // For use in a KDF the hash algorithm does not
1658            // necessarily be collision resistant, but this is the
1659            // weakest property that we otherwise care for, so
1660            // (somewhat arbitrarily) use this.
1661            self
1662                .collision_resistant_hash_algos
1663                .check(*hash, time, None)
1664                .context("Policy rejected ECDH \
1665                          key derivation hash function")?;
1666        }
1667
1668        Ok(())
1669    }
1670
1671    fn packet(&self, packet: &Packet) -> Result<()> {
1672        let time = self.time.unwrap_or_else(Timestamp::now);
1673        self.packet_tags
1674            .check(
1675                packet.tag(),
1676                packet.version().unwrap_or(0),
1677                time, None)
1678            .context("Policy rejected packet type")
1679    }
1680
1681    fn symmetric_algorithm(&self, algo: SymmetricAlgorithm) -> Result<()> {
1682        let time = self.time.unwrap_or_else(Timestamp::now);
1683        self.symmetric_algos.check(algo, time, None)
1684            .context("Policy rejected symmetric encryption algorithm")
1685    }
1686
1687    fn aead_algorithm(&self, algo: AEADAlgorithm) -> Result<()> {
1688        let time = self.time.unwrap_or_else(Timestamp::now);
1689        self.aead_algos.check(algo, time, None)
1690            .context("Policy rejected authenticated encryption algorithm")
1691    }
1692}
1693
1694/// Asymmetric encryption algorithms.
1695///
1696/// This type is for refining the [`StandardPolicy`] with respect to
1697/// asymmetric algorithms.  In contrast to [`PublicKeyAlgorithm`], it
1698/// does not concern itself with the use (encryption or signing), and
1699/// it does include key sizes (if applicable) and elliptic curves.
1700///
1701///   [`PublicKeyAlgorithm`]: crate::types::PublicKeyAlgorithm
1702///
1703/// Key sizes put into are buckets, rounding down to the nearest
1704/// bucket.  For example, a 3253-bit RSA key is categorized as
1705/// `RSA3072`.
1706#[non_exhaustive]
1707#[allow(non_camel_case_types)]
1708#[derive(Clone, Debug, PartialEq, Eq, Copy)]
1709pub enum AsymmetricAlgorithm {
1710    /// RSA with key sizes up to 2048-1 bit.
1711    RSA1024,
1712    /// RSA with key sizes up to 3072-1 bit.
1713    RSA2048,
1714    /// RSA with key sizes up to 4096-1 bit.
1715    RSA3072,
1716    /// RSA with key sizes larger or equal to 4096 bit.
1717    RSA4096,
1718    /// ElGamal with key sizes up to 2048-1 bit.
1719    ElGamal1024,
1720    /// ElGamal with key sizes up to 3072-1 bit.
1721    ElGamal2048,
1722    /// ElGamal with key sizes up to 4096-1 bit.
1723    ElGamal3072,
1724    /// ElGamal with key sizes larger or equal to 4096 bit.
1725    ElGamal4096,
1726    /// DSA with key sizes up to 2048-1 bit.
1727    DSA1024,
1728    /// DSA with key sizes up to 3072-1 bit.
1729    DSA2048,
1730    /// DSA with key sizes up to 4096-1 bit.
1731    DSA3072,
1732    /// DSA with key sizes larger or equal to 4096 bit.
1733    DSA4096,
1734    /// NIST curve P-256.
1735    NistP256,
1736    /// NIST curve P-384.
1737    NistP384,
1738    /// NIST curve P-521.
1739    NistP521,
1740    /// brainpoolP256r1.
1741    BrainpoolP256,
1742    /// brainpoolP384r1.
1743    BrainpoolP384,
1744    /// brainpoolP512r1.
1745    BrainpoolP512,
1746    /// D.J. Bernstein's Curve25519.
1747    Cv25519,
1748    /// X25519 (RFC 7748).
1749    X25519,
1750    /// X448 (RFC 7748).
1751    X448,
1752    /// Ed25519 (RFC 8032).
1753    Ed25519,
1754    /// Ed448 (RFC 8032).
1755    Ed448,
1756    /// EdDSA (v4 Ed25519Legacy)
1757    EdDSA,
1758
1759    /// Composite signature algorithm using ML-DSA-65 and Ed25519.
1760    MLDSA65_Ed25519,
1761
1762    /// Composite signature algorithm using ML-DSA-87 and Ed448.
1763    MLDSA87_Ed448,
1764
1765    /// SLH-DSA signature algorithm SHAKE 128 bit, small signatures.
1766    ///
1767    /// Note: [RFC 9980 only specifies the SHAKE variant of the
1768    /// SLH-DSA
1769    /// algorithm](https://www.rfc-editor.org/rfc/rfc9980.html#name-supported-public-key-algori).
1770    SLHDSA128s,
1771
1772    /// SLH-DSA signature algorithm SHAKE 128 bit, fast signatures.
1773    ///
1774    /// Note: [RFC 9980 only specifies the SHAKE variant of the
1775    /// SLH-DSA
1776    /// algorithm](https://www.rfc-editor.org/rfc/rfc9980.html#name-supported-public-key-algori).
1777    SLHDSA128f,
1778
1779    /// SLH-DSA signature algorithm SHAKE 256 bit, small signatures.
1780    ///
1781    /// Note: [RFC 9980 only specifies the SHAKE variant of the
1782    /// SLH-DSA
1783    /// algorithm](https://www.rfc-editor.org/rfc/rfc9980.html#name-supported-public-key-algori).
1784    SLHDSA256s,
1785
1786    /// Composite KEM using ML-KEM-768 and X25519.
1787    MLKEM768_X25519,
1788
1789    /// Composite KEM using ML-KEM-1024 and X448.
1790    MLKEM1024_X448,
1791
1792    /// Unknown algorithm.
1793    Unknown,
1794}
1795assert_send_and_sync!(AsymmetricAlgorithm);
1796
1797const ASYMMETRIC_ALGORITHM_VARIANTS: [AsymmetricAlgorithm; 31] = [
1798    AsymmetricAlgorithm::RSA1024,
1799    AsymmetricAlgorithm::RSA2048,
1800    AsymmetricAlgorithm::RSA3072,
1801    AsymmetricAlgorithm::RSA4096,
1802    AsymmetricAlgorithm::ElGamal1024,
1803    AsymmetricAlgorithm::ElGamal2048,
1804    AsymmetricAlgorithm::ElGamal3072,
1805    AsymmetricAlgorithm::ElGamal4096,
1806    AsymmetricAlgorithm::DSA1024,
1807    AsymmetricAlgorithm::DSA2048,
1808    AsymmetricAlgorithm::DSA3072,
1809    AsymmetricAlgorithm::DSA4096,
1810    AsymmetricAlgorithm::NistP256,
1811    AsymmetricAlgorithm::NistP384,
1812    AsymmetricAlgorithm::NistP521,
1813    AsymmetricAlgorithm::BrainpoolP256,
1814    AsymmetricAlgorithm::BrainpoolP384,
1815    AsymmetricAlgorithm::BrainpoolP512,
1816    AsymmetricAlgorithm::Cv25519,
1817    AsymmetricAlgorithm::X25519,
1818    AsymmetricAlgorithm::X448,
1819    AsymmetricAlgorithm::Ed25519,
1820    AsymmetricAlgorithm::Ed448,
1821    AsymmetricAlgorithm::EdDSA,
1822    AsymmetricAlgorithm::MLDSA65_Ed25519,
1823    AsymmetricAlgorithm::MLDSA87_Ed448,
1824    AsymmetricAlgorithm::SLHDSA128s,
1825    AsymmetricAlgorithm::SLHDSA128f,
1826    AsymmetricAlgorithm::SLHDSA256s,
1827    AsymmetricAlgorithm::MLKEM768_X25519,
1828    AsymmetricAlgorithm::MLKEM1024_X448,
1829];
1830
1831impl AsymmetricAlgorithm {
1832    /// Returns an iterator over all valid variants.
1833    ///
1834    /// Returns an iterator over all known variants.  This does not
1835    /// include the [`AsymmetricAlgorithm::Unknown`] variant.
1836    pub fn variants() -> impl Iterator<Item=AsymmetricAlgorithm> {
1837        ASYMMETRIC_ALGORITHM_VARIANTS.iter().cloned()
1838    }
1839}
1840
1841impl std::fmt::Display for AsymmetricAlgorithm {
1842    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1843        write!(f, "{:?}", self)
1844    }
1845}
1846
1847impl From<AsymmetricAlgorithm> for u8 {
1848    fn from(a: AsymmetricAlgorithm) -> Self {
1849        use self::AsymmetricAlgorithm::*;
1850        match a {
1851            RSA1024 => 0,
1852            RSA2048 => 1,
1853            RSA3072 => 2,
1854            RSA4096 => 3,
1855            ElGamal1024 => 4,
1856            ElGamal2048 => 5,
1857            ElGamal3072 => 6,
1858            ElGamal4096 => 7,
1859            DSA1024 => 8,
1860            DSA2048 => 9,
1861            DSA3072 => 10,
1862            DSA4096 => 11,
1863            NistP256 => 12,
1864            NistP384 => 13,
1865            NistP521 => 14,
1866            BrainpoolP256 => 15,
1867            BrainpoolP384 => 16,
1868            BrainpoolP512 => 17,
1869            Cv25519 => 18,
1870            X25519 => 19,
1871            X448 => 20,
1872            Ed25519 => 21,
1873            Ed448 => 22,
1874            EdDSA => 23,
1875            MLDSA65_Ed25519 => 24,
1876            MLDSA87_Ed448 => 25,
1877            SLHDSA128s => 26,
1878            SLHDSA128f => 27,
1879            SLHDSA256s => 28,
1880            MLKEM768_X25519 => 29,
1881            MLKEM1024_X448 => 30,
1882            Unknown => 255,
1883        }
1884    }
1885}
1886
1887/// The Null Policy.
1888///
1889/// Danger, here be dragons.
1890///
1891/// This policy imposes no additional policy, i.e., accepts
1892/// everything.  This includes the MD5 hash algorithm, and SED
1893/// packets.
1894///
1895/// The Null policy has a limited set of valid use cases, e.g., packet statistics.
1896/// For other purposes, it is more advisable to use the [`StandardPolicy`] and
1897/// adjust it by selectively allowing items considered insecure by default, e.g.,
1898/// via [`StandardPolicy::accept_hash`] function. If this is still too inflexible
1899/// consider creating a specialized policy based on the [`StandardPolicy`] as
1900/// [the example for `StandardPolicy`] illustrates.
1901///
1902///   [`StandardPolicy::accept_hash`]: StandardPolicy::accept_hash()
1903///   [the example for `StandardPolicy`]: StandardPolicy#examples
1904#[derive(Debug)]
1905pub struct NullPolicy {
1906}
1907
1908assert_send_and_sync!(NullPolicy);
1909
1910impl NullPolicy {
1911    /// Instantiates a new `NullPolicy`.
1912    pub const unsafe fn new() -> Self {
1913        NullPolicy {}
1914    }
1915}
1916
1917impl Policy for NullPolicy {
1918    fn signature(&self, _sig: &Signature, _sec: HashAlgoSecurity) -> Result<()> {
1919        Ok(())
1920    }
1921
1922    fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
1923        -> Result<()>
1924    {
1925        Ok(())
1926    }
1927
1928    fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
1929        Ok(())
1930    }
1931
1932    fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
1933        Ok(())
1934    }
1935
1936    fn packet(&self, _packet: &Packet) -> Result<()> {
1937        Ok(())
1938    }
1939
1940}
1941
1942#[cfg(test)]
1943mod test {
1944    use std::io::Read;
1945    use std::time::Duration;
1946
1947    use super::*;
1948    use crate::Error;
1949    use crate::crypto::SessionKey;
1950    use crate::packet::key::Key4;
1951    use crate::packet::signature;
1952    use crate::packet::{PKESK, SKESK};
1953    use crate::parse::Parse;
1954    use crate::parse::stream::DecryptionHelper;
1955    use crate::parse::stream::DecryptorBuilder;
1956    use crate::parse::stream::DetachedVerifierBuilder;
1957    use crate::parse::stream::MessageLayer;
1958    use crate::parse::stream::MessageStructure;
1959    use crate::parse::stream::VerificationHelper;
1960    use crate::parse::stream::VerifierBuilder;
1961    use crate::policy::StandardPolicy as P;
1962    use crate::types::Curve;
1963    use crate::types::KeyFlags;
1964    use crate::types::SymmetricAlgorithm;
1965
1966    // Test that the constructor is const.
1967    const _A_STANDARD_POLICY: StandardPolicy = StandardPolicy::new();
1968
1969    #[test]
1970    fn binding_signature() {
1971        let p = &P::new();
1972
1973        // A primary and two subkeys.
1974        let (cert, _) = CertBuilder::new()
1975            .add_signing_subkey()
1976            .add_transport_encryption_subkey()
1977            .generate().unwrap();
1978
1979        assert_eq!(cert.keys().with_policy(p, None).count(), 3);
1980
1981        // Reject all direct key signatures.
1982        #[derive(Debug)]
1983        struct NoDirectKeySigs;
1984        impl Policy for NoDirectKeySigs {
1985            fn signature(&self, sig: &Signature, _sec: HashAlgoSecurity)
1986                -> Result<()>
1987            {
1988                use crate::types::SignatureType::*;
1989
1990                match sig.typ() {
1991                    DirectKey => Err(anyhow::anyhow!("direct key!")),
1992                    _ => Ok(()),
1993                }
1994            }
1995
1996            fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
1997                -> Result<()>
1998            {
1999                Ok(())
2000            }
2001
2002            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2003                Ok(())
2004            }
2005
2006            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2007                Ok(())
2008            }
2009
2010            fn packet(&self, _packet: &Packet) -> Result<()> {
2011                Ok(())
2012            }
2013        }
2014
2015        let p = &NoDirectKeySigs {};
2016        assert_eq!(cert.keys().with_policy(p, None).count(), 0);
2017
2018        // Reject all subkey signatures.
2019        #[derive(Debug)]
2020        struct NoSubkeySigs;
2021        impl Policy for NoSubkeySigs {
2022            fn signature(&self, sig: &Signature, _sec: HashAlgoSecurity)
2023                -> Result<()>
2024            {
2025                use crate::types::SignatureType::*;
2026
2027                match sig.typ() {
2028                    SubkeyBinding => Err(anyhow::anyhow!("subkey signature!")),
2029                    _ => Ok(()),
2030                }
2031            }
2032
2033            fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2034                -> Result<()>
2035            {
2036                Ok(())
2037            }
2038
2039            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2040                Ok(())
2041            }
2042
2043            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2044                Ok(())
2045            }
2046
2047            fn packet(&self, _packet: &Packet) -> Result<()> {
2048                Ok(())
2049            }
2050        }
2051
2052        let p = &NoSubkeySigs {};
2053        assert_eq!(cert.keys().with_policy(p, None).count(), 1);
2054    }
2055
2056    #[test]
2057    fn revocation() -> Result<()> {
2058        use crate::cert::prelude::*;
2059        use crate::types::SignatureType;
2060        use crate::types::ReasonForRevocation;
2061
2062        let p = &P::new();
2063
2064        // A primary and two subkeys.
2065        let (cert, _) = CertBuilder::new()
2066            .add_userid("Alice")
2067            .add_signing_subkey()
2068            .add_transport_encryption_subkey()
2069            .generate()?;
2070
2071        // Make sure we have all keys and all user ids.
2072        assert_eq!(cert.keys().with_policy(p, None).count(), 3);
2073        assert_eq!(cert.userids().with_policy(p, None).count(), 1);
2074
2075        // Reject all user id signatures.
2076        #[derive(Debug)]
2077        struct NoPositiveCertifications;
2078        impl Policy for NoPositiveCertifications {
2079            fn signature(&self, sig: &Signature, _sec: HashAlgoSecurity)
2080                -> Result<()>
2081            {
2082                use crate::types::SignatureType::*;
2083                match sig.typ() {
2084                    PositiveCertification =>
2085                        Err(anyhow::anyhow!("positive certification!")),
2086                    _ => Ok(()),
2087                }
2088            }
2089
2090            fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2091                -> Result<()>
2092            {
2093                Ok(())
2094            }
2095
2096            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2097                Ok(())
2098            }
2099
2100            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2101                Ok(())
2102            }
2103
2104            fn packet(&self, _packet: &Packet) -> Result<()> {
2105                Ok(())
2106            }
2107        }
2108        let p = &NoPositiveCertifications {};
2109        assert_eq!(cert.userids().with_policy(p, None).count(), 0);
2110
2111
2112        // Revoke it.
2113        let mut keypair = cert.primary_key().key().clone()
2114            .parts_into_secret()?.into_keypair()?;
2115        let ca = cert.userids().next().unwrap();
2116
2117        // Generate the revocation for the first and only UserID.
2118        let revocation =
2119            UserIDRevocationBuilder::new()
2120            .set_reason_for_revocation(
2121                ReasonForRevocation::KeyRetired,
2122                b"Left example.org.")?
2123            .build(&mut keypair, &cert, ca.userid(), None)?;
2124        assert_eq!(revocation.typ(), SignatureType::CertificationRevocation);
2125
2126        // Now merge the revocation signature into the Cert.
2127        let cert = cert.insert_packets(revocation.clone())?.0;
2128
2129        // Check that it is revoked.
2130        assert_eq!(cert.userids().with_policy(p, None).revoked(false).count(), 0);
2131
2132        // Reject all user id signatures.
2133        #[derive(Debug)]
2134        struct NoCertificationRevocation;
2135        impl Policy for NoCertificationRevocation {
2136            fn signature(&self, sig: &Signature, _sec: HashAlgoSecurity)
2137                -> Result<()>
2138            {
2139                use crate::types::SignatureType::*;
2140                match sig.typ() {
2141                    CertificationRevocation =>
2142                        Err(anyhow::anyhow!("certification certification!")),
2143                    _ => Ok(()),
2144                }
2145            }
2146
2147            fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2148                -> Result<()>
2149            {
2150                Ok(())
2151            }
2152
2153            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2154                Ok(())
2155            }
2156
2157            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2158                Ok(())
2159            }
2160
2161            fn packet(&self, _packet: &Packet) -> Result<()> {
2162                Ok(())
2163            }
2164        }
2165        let p = &NoCertificationRevocation {};
2166
2167        // Check that the user id is no longer revoked.
2168        assert_eq!(cert.userids().with_policy(p, None).revoked(false).count(), 1);
2169
2170
2171        // Generate the revocation for the first subkey.
2172        let subkey = cert.keys().subkeys().next().unwrap();
2173        let revocation =
2174            SubkeyRevocationBuilder::new()
2175                .set_reason_for_revocation(
2176                    ReasonForRevocation::KeyRetired,
2177                    b"Smells funny.").unwrap()
2178                .build(&mut keypair, &cert, subkey.key(), None)?;
2179        assert_eq!(revocation.typ(), SignatureType::SubkeyRevocation);
2180
2181        // Now merge the revocation signature into the Cert.
2182        assert_eq!(cert.keys().with_policy(p, None).revoked(false).count(), 3);
2183        let cert = cert.insert_packets(revocation.clone())?.0;
2184        assert_eq!(cert.keys().with_policy(p, None).revoked(false).count(), 2);
2185
2186        // Reject all subkey revocations.
2187        #[derive(Debug)]
2188        struct NoSubkeyRevocation;
2189        impl Policy for NoSubkeyRevocation {
2190            fn signature(&self, sig: &Signature, _sec: HashAlgoSecurity)
2191                -> Result<()>
2192            {
2193                use crate::types::SignatureType::*;
2194                match sig.typ() {
2195                    SubkeyRevocation =>
2196                        Err(anyhow::anyhow!("subkey revocation!")),
2197                    _ => Ok(()),
2198                }
2199            }
2200
2201            fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2202                -> Result<()>
2203            {
2204                Ok(())
2205            }
2206
2207            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2208                Ok(())
2209            }
2210
2211            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2212                Ok(())
2213            }
2214
2215            fn packet(&self, _packet: &Packet) -> Result<()> {
2216                Ok(())
2217            }
2218        }
2219        let p = &NoSubkeyRevocation {};
2220
2221        // Check that the key is no longer revoked.
2222        assert_eq!(cert.keys().with_policy(p, None).revoked(false).count(), 3);
2223
2224        Ok(())
2225    }
2226
2227
2228    #[test]
2229    fn binary_signature() -> Result<()> {
2230        #[derive(PartialEq, Debug)]
2231        struct VHelper {
2232            good: usize,
2233            errors: usize,
2234            keys: Vec<Cert>,
2235        }
2236
2237        impl VHelper {
2238            fn new(keys: Vec<Cert>) -> Self {
2239                VHelper {
2240                    good: 0,
2241                    errors: 0,
2242                    keys,
2243                }
2244            }
2245        }
2246
2247        impl VerificationHelper for VHelper {
2248            fn get_certs(&mut self, _ids: &[crate::KeyHandle])
2249                -> Result<Vec<Cert>>
2250            {
2251                Ok(self.keys.clone())
2252            }
2253
2254            fn check(&mut self, structure: MessageStructure) -> Result<()>
2255            {
2256                for layer in structure {
2257                    match layer {
2258                        MessageLayer::SignatureGroup { ref results } =>
2259                            for result in results {
2260                                eprintln!("result: {:?}", result);
2261                                match result {
2262                                    Ok(_) => self.good += 1,
2263                                    Err(_) => self.errors += 1,
2264                                }
2265                            }
2266                        MessageLayer::Compression { .. } => (),
2267                        _ => unreachable!(),
2268                    }
2269                }
2270
2271                Ok(())
2272            }
2273        }
2274
2275        impl DecryptionHelper for VHelper {
2276            fn decrypt(&mut self, _: &[PKESK], _: &[SKESK],
2277                       _: Option<SymmetricAlgorithm>,
2278                       _: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool)
2279                       -> Result<Option<Cert>>
2280            {
2281                unreachable!();
2282            }
2283        }
2284
2285        // Reject all data (binary) signatures.
2286        #[derive(Debug)]
2287        struct NoBinarySigantures;
2288        impl Policy for NoBinarySigantures {
2289            fn signature(&self, sig: &Signature, _sec: HashAlgoSecurity)
2290                -> Result<()>
2291            {
2292                use crate::types::SignatureType::*;
2293                eprintln!("{:?}", sig.typ());
2294                match sig.typ() {
2295                    Binary =>
2296                        Err(anyhow::anyhow!("binary!")),
2297                    _ => Ok(()),
2298                }
2299            }
2300
2301            fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2302                -> Result<()>
2303            {
2304                Ok(())
2305            }
2306
2307            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2308                Ok(())
2309            }
2310
2311            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2312                Ok(())
2313            }
2314
2315            fn packet(&self, _packet: &Packet) -> Result<()> {
2316                Ok(())
2317            }
2318        }
2319        let no_binary_signatures = &NoBinarySigantures {};
2320
2321        // Reject all subkey signatures.
2322        #[derive(Debug)]
2323        struct NoSubkeySigs;
2324        impl Policy for NoSubkeySigs {
2325            fn signature(&self, sig: &Signature, _sec: HashAlgoSecurity)
2326                -> Result<()>
2327            {
2328                use crate::types::SignatureType::*;
2329
2330                match sig.typ() {
2331                    SubkeyBinding => Err(anyhow::anyhow!("subkey signature!")),
2332                    _ => Ok(()),
2333                }
2334            }
2335
2336            fn key(&self, _ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2337                -> Result<()>
2338            {
2339                Ok(())
2340            }
2341
2342            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2343                Ok(())
2344            }
2345
2346            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2347                Ok(())
2348            }
2349
2350            fn packet(&self, _packet: &Packet) -> Result<()> {
2351                Ok(())
2352            }
2353        }
2354        let no_subkey_signatures = &NoSubkeySigs {};
2355
2356        let standard = &P::new();
2357
2358        let keys = [
2359            "neal.pgp",
2360        ].iter()
2361            .map(|f| Cert::from_bytes(crate::tests::key(f)).unwrap())
2362            .collect::<Vec<_>>();
2363        let data = "messages/signed-1.pgp";
2364
2365        let reference = crate::tests::manifesto();
2366
2367
2368
2369        // Test Verifier.
2370
2371        // Standard policy => ok.
2372        let h = VHelper::new(keys.clone());
2373        let mut v = VerifierBuilder::from_bytes(crate::tests::file(data))?
2374            .with_policy(standard, crate::frozen_time(), h)?;
2375        assert!(v.message_processed());
2376        assert_eq!(v.helper_ref().good, 1);
2377        assert_eq!(v.helper_ref().errors, 0);
2378
2379        let mut content = Vec::new();
2380        v.read_to_end(&mut content).unwrap();
2381        assert_eq!(reference.len(), content.len());
2382        assert_eq!(reference, &content[..]);
2383
2384
2385        // Kill the subkey.
2386        let h = VHelper::new(keys.clone());
2387        let mut v = VerifierBuilder::from_bytes(crate::tests::file(data))?
2388            .with_policy(no_subkey_signatures, crate::frozen_time(), h)?;
2389        assert!(v.message_processed());
2390        assert_eq!(v.helper_ref().good, 0);
2391        assert_eq!(v.helper_ref().errors, 1);
2392
2393        let mut content = Vec::new();
2394        v.read_to_end(&mut content).unwrap();
2395        assert_eq!(reference.len(), content.len());
2396        assert_eq!(reference, &content[..]);
2397
2398
2399        // Kill the data signature.
2400        let h = VHelper::new(keys.clone());
2401        let mut v = VerifierBuilder::from_bytes(crate::tests::file(data))?
2402            .with_policy(no_binary_signatures, crate::frozen_time(), h)?;
2403        assert!(v.message_processed());
2404        assert_eq!(v.helper_ref().good, 0);
2405        assert_eq!(v.helper_ref().errors, 1);
2406
2407        let mut content = Vec::new();
2408        v.read_to_end(&mut content).unwrap();
2409        assert_eq!(reference.len(), content.len());
2410        assert_eq!(reference, &content[..]);
2411
2412
2413
2414        // Test Decryptor.
2415
2416        // Standard policy.
2417        let h = VHelper::new(keys.clone());
2418        let mut v = DecryptorBuilder::from_bytes(crate::tests::file(data))?
2419            .with_policy(standard, crate::frozen_time(), h)?;
2420        assert!(v.message_processed());
2421        assert_eq!(v.helper_ref().good, 1);
2422        assert_eq!(v.helper_ref().errors, 0);
2423
2424        let mut content = Vec::new();
2425        v.read_to_end(&mut content).unwrap();
2426        assert_eq!(reference.len(), content.len());
2427        assert_eq!(reference, &content[..]);
2428
2429
2430        // Kill the subkey.
2431        let h = VHelper::new(keys.clone());
2432        let mut v = DecryptorBuilder::from_bytes(crate::tests::file(data))?
2433            .with_policy(no_subkey_signatures, crate::frozen_time(), h)?;
2434        assert!(v.message_processed());
2435        assert_eq!(v.helper_ref().good, 0);
2436        assert_eq!(v.helper_ref().errors, 1);
2437
2438        let mut content = Vec::new();
2439        v.read_to_end(&mut content).unwrap();
2440        assert_eq!(reference.len(), content.len());
2441        assert_eq!(reference, &content[..]);
2442
2443
2444        // Kill the data signature.
2445        let h = VHelper::new(keys.clone());
2446        let mut v = DecryptorBuilder::from_bytes(crate::tests::file(data))?
2447            .with_policy(no_binary_signatures, crate::frozen_time(), h)?;
2448        assert!(v.message_processed());
2449        assert_eq!(v.helper_ref().good, 0);
2450        assert_eq!(v.helper_ref().errors, 1);
2451
2452        let mut content = Vec::new();
2453        v.read_to_end(&mut content).unwrap();
2454        assert_eq!(reference.len(), content.len());
2455        assert_eq!(reference, &content[..]);
2456        Ok(())
2457    }
2458
2459    #[test]
2460    fn hash_algo() -> Result<()> {
2461        use crate::types::RevocationStatus;
2462        use crate::types::ReasonForRevocation;
2463
2464        const SECS_IN_YEAR : u64 = 365 * 24 * 60 * 60;
2465
2466        // A `const fn` is only guaranteed to be evaluated at compile
2467        // time if the result is assigned to a `const` variable.  Make
2468        // sure that works.
2469        const DEFAULT : StandardPolicy = StandardPolicy::new();
2470
2471        let (cert, _) = CertBuilder::new()
2472            .add_userid("Alice")
2473            .generate()?;
2474
2475        let algo = cert.primary_key()
2476            .binding_signature(&DEFAULT, None).unwrap().hash_algo();
2477
2478        eprintln!("{:?}", algo);
2479
2480        // Create a revoked version.
2481        let mut keypair = cert.primary_key().key().clone()
2482            .parts_into_secret()?.into_keypair()?;
2483        let rev = cert.revoke(
2484            &mut keypair,
2485            ReasonForRevocation::KeyCompromised,
2486            b"It was the maid :/")?;
2487        let cert_revoked = cert.clone().insert_packets(rev)?.0;
2488
2489        match cert_revoked.revocation_status(&DEFAULT, None) {
2490            RevocationStatus::Revoked(sigs) => {
2491                assert_eq!(sigs.len(), 1);
2492                assert_eq!(sigs[0].hash_algo(), algo);
2493            }
2494            _ => panic!("not revoked"),
2495        }
2496
2497
2498        // Reject the hash algorithm unconditionally.
2499        let mut reject : StandardPolicy = StandardPolicy::new();
2500        reject.reject_hash(algo);
2501        assert!(cert.primary_key()
2502                    .binding_signature(&reject, None).is_err());
2503        assert_match!(RevocationStatus::NotAsFarAsWeKnow
2504                      = cert_revoked.revocation_status(&reject, None));
2505
2506        // Reject the hash algorithm next year.
2507        let mut reject : StandardPolicy = StandardPolicy::new();
2508        reject.reject_hash_at(
2509            algo,
2510            crate::now().checked_add(Duration::from_secs(SECS_IN_YEAR)));
2511        reject.hash_revocation_tolerance(0);
2512        cert.primary_key().binding_signature(&reject, None)?;
2513        assert_match!(RevocationStatus::Revoked(_)
2514                      = cert_revoked.revocation_status(&reject, None));
2515
2516        // Reject the hash algorithm last year.
2517        let mut reject : StandardPolicy = StandardPolicy::new();
2518        reject.reject_hash_at(
2519            algo,
2520            crate::now().checked_sub(Duration::from_secs(SECS_IN_YEAR)));
2521        reject.hash_revocation_tolerance(0);
2522        assert!(cert.primary_key()
2523                    .binding_signature(&reject, None).is_err());
2524        assert_match!(RevocationStatus::NotAsFarAsWeKnow
2525                      = cert_revoked.revocation_status(&reject, None));
2526
2527        // Reject the hash algorithm for normal signatures last year,
2528        // and revocations next year.
2529        let mut reject : StandardPolicy = StandardPolicy::new();
2530        reject.reject_hash_at(
2531            algo,
2532            crate::now().checked_sub(Duration::from_secs(SECS_IN_YEAR)));
2533        reject.hash_revocation_tolerance(2 * SECS_IN_YEAR as u32);
2534        assert!(cert.primary_key()
2535                    .binding_signature(&reject, None).is_err());
2536        assert_match!(RevocationStatus::Revoked(_)
2537                      = cert_revoked.revocation_status(&reject, None));
2538
2539        // Accept algo, but reject the algos with id - 1 and id + 1.
2540        let mut reject : StandardPolicy = StandardPolicy::new();
2541        let algo_u8 : u8 = algo.into();
2542        assert!(algo_u8 != 0u8);
2543        reject.reject_hash_at(
2544            (algo_u8 - 1).into(),
2545            crate::now().checked_sub(Duration::from_secs(SECS_IN_YEAR)));
2546        reject.reject_hash_at(
2547            (algo_u8 + 1).into(),
2548            crate::now().checked_sub(Duration::from_secs(SECS_IN_YEAR)));
2549        reject.hash_revocation_tolerance(0);
2550        cert.primary_key().binding_signature(&reject, None)?;
2551        assert_match!(RevocationStatus::Revoked(_)
2552                      = cert_revoked.revocation_status(&reject, None));
2553
2554        // Reject the hash algorithm since before the Unix epoch.
2555        // Since the earliest representable time using a Timestamp is
2556        // the Unix epoch, this is equivalent to rejecting everything.
2557        let mut reject : StandardPolicy = StandardPolicy::new();
2558        reject.reject_hash_at(
2559            algo,
2560            crate::now().checked_sub(Duration::from_secs(SECS_IN_YEAR)));
2561        reject.hash_revocation_tolerance(0);
2562        assert!(cert.primary_key()
2563                    .binding_signature(&reject, None).is_err());
2564        assert_match!(RevocationStatus::NotAsFarAsWeKnow
2565                      = cert_revoked.revocation_status(&reject, None));
2566
2567        // Reject the hash algorithm after the end of time that is
2568        // representable by a Timestamp (2106).  This should accept
2569        // everything.
2570        let mut reject : StandardPolicy = StandardPolicy::new();
2571        reject.reject_hash_at(
2572            algo,
2573            SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(500 * SECS_IN_YEAR)));
2574        reject.hash_revocation_tolerance(0);
2575        cert.primary_key().binding_signature(&reject, None)?;
2576        assert_match!(RevocationStatus::Revoked(_)
2577                      = cert_revoked.revocation_status(&reject, None));
2578
2579        Ok(())
2580    }
2581
2582    #[test]
2583    fn key_verify_self_signature() -> Result<()> {
2584        let p = &P::new();
2585
2586        #[derive(Debug)]
2587        struct NoRsa;
2588        impl Policy for NoRsa {
2589            fn key(&self, ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2590                   -> Result<()>
2591            {
2592                use crate::types::PublicKeyAlgorithm::*;
2593
2594                eprintln!("algo: {}", ka.key().pk_algo());
2595                if ka.key().pk_algo() == RSAEncryptSign {
2596                    Err(anyhow::anyhow!("RSA!"))
2597                } else {
2598                    Ok(())
2599                }
2600            }
2601
2602            fn signature(&self, _sig: &Signature, _sec: HashAlgoSecurity) -> Result<()> {
2603                Ok(())
2604            }
2605
2606            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2607                Ok(())
2608            }
2609
2610            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2611                Ok(())
2612            }
2613
2614            fn packet(&self, _packet: &Packet) -> Result<()> {
2615                Ok(())
2616            }
2617        }
2618        let norsa = &NoRsa {};
2619
2620        // Generate a certificate with an RSA primary and two RSA
2621        // subkeys.
2622        let (cert,_) = CertBuilder::new()
2623            .set_cipher_suite(CipherSuite::RSA2k)
2624            .add_signing_subkey()
2625            .add_signing_subkey()
2626            .generate()?;
2627        assert_eq!(cert.keys().with_policy(p, None).count(), 3);
2628        assert_eq!(cert.keys().with_policy(norsa, None).count(), 0);
2629        assert!(cert.primary_key().with_policy(p, None).is_ok());
2630        assert!(cert.primary_key().with_policy(norsa, None).is_err());
2631
2632        // Generate a certificate with an ECC primary, an ECC subkey,
2633        // and an RSA subkey.
2634        let (cert,_) = CertBuilder::new()
2635            .set_cipher_suite(CipherSuite::Cv25519)
2636            .add_signing_subkey()
2637            .generate()?;
2638
2639        let pk = cert.primary_key().key().parts_as_secret()?;
2640        let subkey: key::SecretSubkey
2641            = Key4::generate_rsa(2048)?.into();
2642        let binding = signature::SignatureBuilder::new(SignatureType::SubkeyBinding)
2643            .set_key_flags(KeyFlags::empty().set_transport_encryption())?
2644            .sign_subkey_binding(&mut pk.clone().into_keypair()?,
2645                                 pk.parts_as_public(), &subkey)?;
2646
2647        let cert = cert.insert_packets(
2648            vec![ Packet::from(subkey), binding.into() ])?.0;
2649
2650        assert_eq!(cert.keys().with_policy(p, None).count(), 3);
2651        assert_eq!(cert.keys().with_policy(norsa, None).count(), 2);
2652        assert!(cert.primary_key().with_policy(p, None).is_ok());
2653        assert!(cert.primary_key().with_policy(norsa, None).is_ok());
2654
2655        // Generate a certificate with an RSA primary, an RSA subkey,
2656        // and an ECC subkey.
2657        let (cert,_) = CertBuilder::new()
2658            .set_cipher_suite(CipherSuite::RSA2k)
2659            .add_signing_subkey()
2660            .generate()?;
2661
2662        let pk = cert.primary_key().key().parts_as_secret()?;
2663        let subkey: key::SecretSubkey
2664            = key::Key6::generate_ecc(true, Curve::Ed25519)?.into();
2665        let binding = signature::SignatureBuilder::new(SignatureType::SubkeyBinding)
2666            .set_key_flags(KeyFlags::empty().set_transport_encryption())?
2667            .sign_subkey_binding(&mut pk.clone().into_keypair()?,
2668                                 pk.parts_as_public(), &subkey)?;
2669
2670        let cert = cert.insert_packets(
2671            vec![ Packet::from(subkey), binding.into() ])?.0;
2672
2673        assert_eq!(cert.keys().with_policy(p, None).count(), 3);
2674        assert_eq!(cert.keys().with_policy(norsa, None).count(), 0);
2675        assert!(cert.primary_key().with_policy(p, None).is_ok());
2676        assert!(cert.primary_key().with_policy(norsa, None).is_err());
2677
2678        // Generate a certificate with an ECC primary and two ECC
2679        // subkeys.
2680        let (cert,_) = CertBuilder::new()
2681            .set_cipher_suite(CipherSuite::Cv25519)
2682            .add_signing_subkey()
2683            .add_signing_subkey()
2684            .generate()?;
2685        assert_eq!(cert.keys().with_policy(p, None).count(), 3);
2686        assert_eq!(cert.keys().with_policy(norsa, None).count(), 3);
2687        assert!(cert.primary_key().with_policy(p, None).is_ok());
2688        assert!(cert.primary_key().with_policy(norsa, None).is_ok());
2689
2690        Ok(())
2691    }
2692
2693    #[test]
2694    fn key_verify_binary_signature() -> Result<()> {
2695        use crate::packet::signature;
2696        use crate::serialize::SerializeInto;
2697        use crate::Packet;
2698        use crate::types::KeyFlags;
2699
2700        let p = &P::new();
2701
2702        #[derive(Debug)]
2703        struct NoRsa;
2704        impl Policy for NoRsa {
2705            fn key(&self, ka: &ValidErasedKeyAmalgamation<key::PublicParts>)
2706                   -> Result<()>
2707            {
2708                use crate::types::PublicKeyAlgorithm::*;
2709
2710                eprintln!("algo: {} is {}",
2711                          ka.key().fingerprint(), ka.key().pk_algo());
2712                if ka.key().pk_algo() == RSAEncryptSign {
2713                    Err(anyhow::anyhow!("RSA!"))
2714                } else {
2715                    Ok(())
2716                }
2717            }
2718
2719            fn signature(&self, _sig: &Signature, _sec: HashAlgoSecurity) -> Result<()> {
2720                Ok(())
2721            }
2722
2723            fn symmetric_algorithm(&self, _algo: SymmetricAlgorithm) -> Result<()> {
2724                Ok(())
2725            }
2726
2727            fn aead_algorithm(&self, _algo: AEADAlgorithm) -> Result<()> {
2728                Ok(())
2729            }
2730
2731            fn packet(&self, _packet: &Packet) -> Result<()> {
2732                Ok(())
2733            }
2734        }
2735        let norsa = &NoRsa {};
2736
2737        #[derive(PartialEq, Debug)]
2738        struct VHelper {
2739            good: usize,
2740            errors: usize,
2741            keys: Vec<Cert>,
2742        }
2743
2744        impl VHelper {
2745            fn new(keys: Vec<Cert>) -> Self {
2746                VHelper {
2747                    good: 0,
2748                    errors: 0,
2749                    keys,
2750                }
2751            }
2752        }
2753
2754        impl VerificationHelper for VHelper {
2755            fn get_certs(&mut self, _ids: &[crate::KeyHandle])
2756                -> Result<Vec<Cert>>
2757            {
2758                Ok(self.keys.clone())
2759            }
2760
2761            fn check(&mut self, structure: MessageStructure) -> Result<()>
2762            {
2763                for layer in structure {
2764                    match layer {
2765                        MessageLayer::SignatureGroup { ref results } =>
2766                            for result in results {
2767                                match result {
2768                                    Ok(_) => self.good += 1,
2769                                    Err(e) => {
2770                                        eprintln!("{}", e);
2771                                        self.errors += 1
2772                                    },
2773                                }
2774                            }
2775                        MessageLayer::Compression { .. } => (),
2776                        _ => unreachable!(),
2777                    }
2778                }
2779
2780                Ok(())
2781            }
2782        }
2783
2784        impl DecryptionHelper for VHelper {
2785            fn decrypt(&mut self, _: &[PKESK], _: &[SKESK],
2786                       _: Option<SymmetricAlgorithm>,
2787                       _: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool)
2788                       -> Result<Option<Cert>>
2789            {
2790                unreachable!();
2791            }
2792        }
2793
2794        // Sign msg using cert's first subkey, return the signature.
2795        fn sign_and_verify(p: &dyn Policy, cert: &Cert, good: bool) {
2796            eprintln!("Expect verification to be {}",
2797                      if good { "good" } else { "bad" });
2798            for (i, k) in cert.keys().enumerate() {
2799                eprintln!("  {}. {}", i, k.key().fingerprint());
2800            }
2801
2802            let msg = b"Hello, World";
2803
2804            // We always use the first subkey.
2805            let key = cert.keys().nth(1).unwrap().key();
2806            let mut keypair = key.clone()
2807                .parts_into_secret().unwrap()
2808                .into_keypair().unwrap();
2809
2810            // Create a signature.
2811            let sig =
2812                signature::SignatureBuilder::new(SignatureType::Binary)
2813                .sign_message(&mut keypair, msg).unwrap();
2814
2815            // Make sure the signature is ok.
2816            sig.verify_message(key, msg).unwrap();
2817
2818            // Turn it into a detached signature.
2819            let sig = Packet::from(sig).to_vec().unwrap();
2820
2821            let h = VHelper::new(vec![ cert.clone() ]);
2822            let mut v = DetachedVerifierBuilder::from_bytes(&sig).unwrap()
2823                .with_policy(p, None, h).unwrap();
2824            v.verify_bytes(msg).unwrap();
2825            assert_eq!(v.helper_ref().good, if good { 1 } else { 0 });
2826            assert_eq!(v.helper_ref().errors, if good { 0 } else { 1 });
2827        }
2828
2829
2830        // A certificate with an ECC primary and an ECC signing
2831        // subkey.
2832        eprintln!("Trying ECC primary, ECC sub:");
2833        let (cert,_) = CertBuilder::new()
2834            .set_cipher_suite(CipherSuite::Cv25519)
2835            .add_subkey(KeyFlags::empty().set_signing(), None,
2836                        None)
2837            .generate()?;
2838
2839        assert_eq!(cert.keys().with_policy(p, None).count(), 2);
2840        assert_eq!(cert.keys().with_policy(norsa, None).count(), 2);
2841        assert!(cert.primary_key().with_policy(p, None).is_ok());
2842        assert!(cert.primary_key().with_policy(norsa, None).is_ok());
2843
2844        sign_and_verify(p, &cert, true);
2845        sign_and_verify(norsa, &cert, true);
2846
2847        // A certificate with an RSA primary and an RCC signing
2848        // subkey.
2849        eprintln!("Trying RSA primary, ECC sub:");
2850        let (cert,_) = CertBuilder::new()
2851            .set_cipher_suite(CipherSuite::RSA2k)
2852            .add_subkey(KeyFlags::empty().set_signing(), None,
2853                        CipherSuite::Cv25519)
2854            .generate()?;
2855
2856        assert_eq!(cert.keys().with_policy(p, None).count(), 2);
2857        assert_eq!(cert.keys().with_policy(norsa, None).count(), 0);
2858        assert!(cert.primary_key().with_policy(p, None).is_ok());
2859        assert!(cert.primary_key().with_policy(norsa, None).is_err());
2860
2861        sign_and_verify(p, &cert, true);
2862        sign_and_verify(norsa, &cert, false);
2863
2864        // A certificate with an ECC primary and an RSA signing
2865        // subkey.
2866        eprintln!("Trying ECC primary, RSA sub:");
2867        let (cert,_) = CertBuilder::new()
2868            .set_cipher_suite(CipherSuite::Cv25519)
2869            .add_subkey(KeyFlags::empty().set_signing(), None,
2870                        CipherSuite::RSA2k)
2871            .generate()?;
2872
2873        assert_eq!(cert.keys().with_policy(p, None).count(), 2);
2874        assert_eq!(cert.keys().with_policy(norsa, None).count(), 1);
2875        assert!(cert.primary_key().with_policy(p, None).is_ok());
2876        assert!(cert.primary_key().with_policy(norsa, None).is_ok());
2877
2878        sign_and_verify(p, &cert, true);
2879        sign_and_verify(norsa, &cert, false);
2880
2881        Ok(())
2882    }
2883
2884    #[test]
2885    fn reject_seip_packet() -> Result<()> {
2886        #[derive(PartialEq, Debug)]
2887        struct Helper {}
2888        impl VerificationHelper for Helper {
2889            fn get_certs(&mut self, _: &[crate::KeyHandle])
2890                -> Result<Vec<Cert>> {
2891                unreachable!()
2892            }
2893
2894            fn check(&mut self, _: MessageStructure) -> Result<()> {
2895                unreachable!()
2896            }
2897        }
2898
2899        impl DecryptionHelper for Helper {
2900            fn decrypt(&mut self, _: &[PKESK], _: &[SKESK],
2901                       _: Option<SymmetricAlgorithm>,
2902                       _: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool)
2903                       -> Result<Option<Cert>>
2904            {
2905                Ok(None)
2906            }
2907        }
2908
2909        let p = &P::new();
2910        let r = DecryptorBuilder::from_bytes(crate::tests::message(
2911                "encrypted-to-testy.pgp"))?
2912            .with_policy(p, crate::frozen_time(), Helper {});
2913        match r {
2914            Ok(_) => panic!(),
2915            Err(e) => assert_match!(Error::MissingSessionKey(_)
2916                                    = e.downcast().unwrap()),
2917        }
2918
2919        // Reject the SEIP packet.
2920        let p = &mut P::new();
2921        p.reject_packet_tag(Tag::SEIP);
2922        let r = DecryptorBuilder::from_bytes(crate::tests::message(
2923                "encrypted-to-testy.pgp"))?
2924            .with_policy(p, crate::frozen_time(), Helper {});
2925        match r {
2926            Ok(_) => panic!(),
2927            Err(e) => assert_match!(Error::PolicyViolation(_, _)
2928                                    = e.downcast().unwrap()),
2929        }
2930        Ok(())
2931    }
2932
2933    #[test]
2934    fn reject_cipher() -> Result<()> {
2935        struct Helper {}
2936        impl VerificationHelper for Helper {
2937            fn get_certs(&mut self, _: &[crate::KeyHandle])
2938                -> Result<Vec<Cert>> {
2939                Ok(Default::default())
2940            }
2941
2942            fn check(&mut self, _: MessageStructure) -> Result<()> {
2943                Ok(())
2944            }
2945        }
2946
2947        impl DecryptionHelper for Helper {
2948            fn decrypt(&mut self, pkesks: &[PKESK], _: &[SKESK],
2949                       algo: Option<SymmetricAlgorithm>,
2950                       decrypt: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool)
2951                       -> Result<Option<Cert>>
2952            {
2953                let p = &P::new();
2954                let mut pair = Cert::from_bytes(
2955                    crate::tests::key("testy-private.pgp"))?
2956                    .keys().with_policy(p, None)
2957                    .for_transport_encryption().secret().next().unwrap()
2958                    .key().clone().into_keypair()?;
2959                pkesks[0].decrypt(&mut pair, algo)
2960                    .map(|(algo, session_key)| decrypt(algo, &session_key));
2961                Ok(None)
2962            }
2963        }
2964
2965        let p = &P::new();
2966        DecryptorBuilder::from_bytes(crate::tests::message(
2967                "encrypted-to-testy-no-compression.pgp"))?
2968            .with_policy(p, crate::frozen_time(), Helper {})?;
2969
2970        // Reject the AES256.
2971        let p = &mut P::new();
2972        p.reject_symmetric_algo(SymmetricAlgorithm::AES256);
2973        let r = DecryptorBuilder::from_bytes(crate::tests::message(
2974                "encrypted-to-testy-no-compression.pgp"))?
2975            .with_policy(p, crate::frozen_time(), Helper {});
2976        match r {
2977            Ok(_) => panic!(),
2978            Err(e) => assert_match!(Error::PolicyViolation(_, _)
2979                                    = e.downcast().unwrap()),
2980        }
2981        Ok(())
2982    }
2983
2984    #[test]
2985    fn reject_asymmetric_algos() -> Result<()> {
2986        let cert = Cert::from_bytes(crate::tests::key("neal.pgp"))?;
2987        let p = &mut P::new();
2988        let t = crate::frozen_time();
2989
2990        assert_eq!(cert.with_policy(p, t).unwrap().keys().count(), 4);
2991        p.reject_asymmetric_algo(AsymmetricAlgorithm::RSA1024);
2992        assert_eq!(cert.with_policy(p, t).unwrap().keys().count(), 4);
2993        p.reject_asymmetric_algo(AsymmetricAlgorithm::RSA2048);
2994        assert_eq!(cert.with_policy(p, t).unwrap().keys().count(), 1);
2995        Ok(())
2996    }
2997
2998    #[test]
2999    fn reject_all_hashes() -> Result<()> {
3000        let mut p = StandardPolicy::new();
3001
3002        let set_variants = [
3003            HashAlgorithm::MD5,
3004            HashAlgorithm::Unknown(234),
3005        ];
3006        let check_variants = [
3007            HashAlgorithm::SHA512,
3008            HashAlgorithm::Unknown(239),
3009        ];
3010
3011        // Accept a few hashes explicitly.
3012        for v in set_variants.iter().cloned() {
3013            p.accept_hash(v);
3014            assert_eq!(
3015                p.hash_cutoff(
3016                    v,
3017                    HashAlgoSecurity::SecondPreImageResistance),
3018                ACCEPT.map(Into::into));
3019            assert_eq!(
3020                p.hash_cutoff(
3021                    v,
3022                    HashAlgoSecurity::CollisionResistance),
3023                ACCEPT.map(Into::into));
3024        }
3025
3026        // Reject all hashes.
3027        p.reject_all_hashes();
3028
3029        for v in set_variants.iter().chain(check_variants.iter()).cloned() {
3030            assert_eq!(
3031                p.hash_cutoff(
3032                    v,
3033                    HashAlgoSecurity::SecondPreImageResistance),
3034                REJECT.map(Into::into));
3035            assert_eq!(
3036                p.hash_cutoff(
3037                    v,
3038                    HashAlgoSecurity::CollisionResistance),
3039                REJECT.map(Into::into));
3040        }
3041
3042        Ok(())
3043    }
3044
3045    macro_rules! reject_all_check {
3046        ($reject_all:ident, $accept_one:ident, $cutoff:ident,
3047         $set_variants:expr, $check_variants:expr) => {
3048            #[test]
3049            fn $reject_all() -> Result<()> {
3050                let mut p = StandardPolicy::new();
3051
3052                // Accept a few hashes explicitly.
3053                for v in $set_variants.iter().cloned() {
3054                    p.$accept_one(v);
3055                    assert_eq!(p.$cutoff(v), ACCEPT.map(Into::into));
3056                }
3057
3058                // Reject all hashes.
3059                p.$reject_all();
3060
3061                for v in $set_variants.iter()
3062                    .chain($check_variants.iter()).cloned()
3063                {
3064                    assert_eq!(
3065                        p.$cutoff(v),
3066                        REJECT.map(Into::into));
3067                }
3068                Ok(())
3069            }
3070        }
3071    }
3072
3073    reject_all_check!(reject_all_critical_subpackets,
3074                      accept_critical_subpacket,
3075                      critical_subpacket_cutoff,
3076                      &[ SubpacketTag::TrustSignature,
3077                         SubpacketTag::Unknown(252) ],
3078                      &[ SubpacketTag::Unknown(253),
3079                         SubpacketTag::SignatureCreationTime ]);
3080
3081    reject_all_check!(reject_all_asymmetric_algos,
3082                      accept_asymmetric_algo,
3083                      asymmetric_algo_cutoff,
3084                      &[ AsymmetricAlgorithm::RSA3072,
3085                         AsymmetricAlgorithm::Cv25519 ],
3086                      &[ AsymmetricAlgorithm::Unknown,
3087                         AsymmetricAlgorithm::NistP256 ]);
3088
3089    reject_all_check!(reject_all_symmetric_algos,
3090                      accept_symmetric_algo,
3091                      symmetric_algo_cutoff,
3092                      &[ SymmetricAlgorithm::Unencrypted,
3093                         SymmetricAlgorithm::Unknown(252) ],
3094                      &[ SymmetricAlgorithm::AES256,
3095                         SymmetricAlgorithm::Unknown(230) ]);
3096
3097    reject_all_check!(reject_all_aead_algos,
3098                      accept_aead_algo,
3099                      aead_algo_cutoff,
3100                      &[ AEADAlgorithm::OCB ],
3101                      &[ AEADAlgorithm::EAX ]);
3102
3103    #[test]
3104    fn reject_all_packets() -> Result<()> {
3105        let mut p = StandardPolicy::new();
3106
3107        let set_variants = [
3108            (Tag::SEIP, 4),
3109            (Tag::Unknown(252), 17),
3110        ];
3111        let check_variants = [
3112            (Tag::Signature, 4),
3113            (Tag::Unknown(230), 9),
3114        ];
3115
3116        // Accept a few packets explicitly.
3117        for (t, v) in set_variants.iter().cloned() {
3118            p.accept_packet_tag_version(t, v);
3119            assert_eq!(
3120                p.packet_tag_version_cutoff(t, v),
3121                ACCEPT.map(Into::into));
3122        }
3123
3124        // Reject all hashes.
3125        p.reject_all_packet_tags();
3126
3127        for (t, v) in set_variants.iter().chain(check_variants.iter()).cloned() {
3128            assert_eq!(
3129                p.packet_tag_version_cutoff(t, v),
3130                REJECT.map(Into::into));
3131        }
3132
3133        Ok(())
3134    }
3135
3136    #[test]
3137    fn packet_versions() -> Result<()> {
3138        // Accept the version of a packet.  Optionally make sure a
3139        // different version is not accepted.
3140        fn accept_and_check(p: &mut StandardPolicy,
3141                            tag: Tag,
3142                            accept_versions: &[u8],
3143                            good_versions: &[u8],
3144                            bad_versions: &[u8]) {
3145            for v in accept_versions {
3146                p.accept_packet_tag_version(tag, *v);
3147                assert_eq!(
3148                    p.packet_tag_version_cutoff(tag, *v),
3149                    ACCEPT.map(Into::into));
3150            }
3151
3152            for v in good_versions.iter() {
3153                assert_eq!(
3154                    p.packet_tag_version_cutoff(tag, *v),
3155                    ACCEPT.map(Into::into));
3156            }
3157            for v in bad_versions.iter() {
3158                assert_eq!(
3159                    p.packet_tag_version_cutoff(tag, *v),
3160                    REJECT.map(Into::into));
3161            }
3162        }
3163
3164        use rand::seq::SliceRandom;
3165        let mut rng = rand::rng();
3166
3167        let mut all_versions = (0..=u8::MAX).collect::<Vec<_>>();
3168        all_versions.shuffle(&mut rng);
3169        let all_versions = &all_versions[..];
3170        let mut not_v5 = all_versions.iter()
3171            .filter(|&&v| v != 5)
3172            .cloned()
3173            .collect::<Vec<_>>();
3174        not_v5.shuffle(&mut rng);
3175        let not_v5 = &not_v5[..];
3176
3177        let p = &mut StandardPolicy::new();
3178        p.reject_all_packet_tags();
3179
3180        // First only use the versioned interfaces.
3181        accept_and_check(p, Tag::Signature, &[3], &[], &[4, 5]);
3182        accept_and_check(p, Tag::Signature, &[4], &[3], &[5]);
3183
3184        // Only use an unversioned policy.
3185        accept_and_check(p, Tag::SEIP,
3186                         &[], // set to accept
3187                         &[], // good
3188                         all_versions, // bad
3189        );
3190        p.accept_packet_tag(Tag::SEIP);
3191        accept_and_check(p, Tag::SEIP,
3192                         &[], // set to accept
3193                         all_versions, // good
3194                         &[], // bad
3195        );
3196
3197        // Set an unversioned policy and then a versioned policy.
3198        accept_and_check(p, Tag::PKESK,
3199                         &[], // set to accept
3200                         &[], // good
3201                         all_versions, // bad
3202        );
3203        p.accept_packet_tag(Tag::PKESK);
3204        accept_and_check(p, Tag::PKESK,
3205                         &[], // set to accept
3206                         &(0..u8::MAX).collect::<Vec<_>>()[..], // good
3207                         &[], // bad
3208        );
3209        p.reject_packet_tag_version(Tag::PKESK, 5);
3210        accept_and_check(p, Tag::PKESK,
3211                         &[], // set to accept
3212                         not_v5, // good
3213                         &[5], // bad
3214        );
3215
3216        // Set a versioned policy and then an unversioned policy.
3217        // Make sure that the versioned policy is cleared by the
3218        // unversioned policy.
3219        accept_and_check(p, Tag::SKESK,
3220                         &[], // set to accept
3221                         &[], // good
3222                         all_versions, // bad
3223        );
3224        p.accept_packet_tag_version(Tag::SKESK, 5);
3225        accept_and_check(p, Tag::SKESK,
3226                         &[], // set to accept
3227                         &[5], // good
3228                         not_v5, // bad
3229        );
3230        p.reject_packet_tag(Tag::SKESK);
3231        // All versions should be bad now...
3232        accept_and_check(p, Tag::SKESK,
3233                         &[], // set to accept
3234                         &[], // good
3235                         all_versions, // bad
3236        );
3237
3238        Ok(())
3239    }
3240}