From e5712889a0f6f678323ed86c6aad54b807694a7c Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Fri, 11 Dec 2020 15:16:45 +0100 Subject: sq: Add switch to fall back to an expired encryption subkey. --- sq/src/commands/mod.rs | 34 +++++++++++++++++++++++++++++++--- sq/src/sq-usage.rs | 10 ++++++---- sq/src/sq.rs | 4 +++- sq/src/sq_cli.rs | 5 +++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/sq/src/commands/mod.rs b/sq/src/commands/mod.rs index 83a02237..06110976 100644 --- a/sq/src/commands/mod.rs +++ b/sq/src/commands/mod.rs @@ -81,7 +81,9 @@ pub fn encrypt<'a>(policy: &'a dyn Policy, npasswords: usize, recipients: &'a [openpgp::Cert], signers: Vec, mode: openpgp::types::KeyFlags, compression: &str, - time: Option) + time: Option, + use_expired_subkey: bool, +) -> Result<()> { let mut passwords: Vec = Vec::with_capacity(npasswords); for n in 0..npasswords { @@ -112,8 +114,34 @@ pub fn encrypt<'a>(policy: &'a dyn Policy, count += 1; } if count == 0 { - return Err(anyhow::anyhow!( - "Key {} has no suitable encryption key", cert)); + let mut expired_keys = Vec::new(); + for ka in cert.keys().with_policy(policy, None).revoked(false) + .key_flags(&mode).supported() + { + let key = ka.key(); + expired_keys.push( + (ka.binding_signature().key_expiration_time(key) + .expect("Key must have an expiration time"), + key)); + } + expired_keys.sort_by_key(|(expiration_time, _)| *expiration_time); + + if let Some((expiration_time, key)) = expired_keys.last() { + if use_expired_subkey { + recipient_subkeys.push((*key).into()); + } else { + use chrono::{DateTime, offset::Utc}; + return Err(anyhow::anyhow!( + "The last suitable encryption key of cert {} expired \ + on {}\n\ + Hint: Use --use-expired-subkey to use it anyway.", + cert, + DateTime::::from(*expiration_time))); + } + } else { + return Err(anyhow::anyhow!( + "Cert {} has no suitable encryption key", cert)); + } } } diff --git a/sq/src/sq-usage.rs b/sq/src/sq-usage.rs index 2729cafa..28e3085a 100644 --- a/sq/src/sq-usage.rs +++ b/sq/src/sq-usage.rs @@ -74,10 +74,12 @@ //! sq encrypt [FLAGS] [OPTIONS] [--] [FILE] //! //! FLAGS: -//! -B, --binary Don't ASCII-armor encode the OpenPGP data -//! -h, --help Prints help information -//! -s, --symmetric Encrypt with a password (can be given multiple times) -//! -V, --version Prints version information +//! -B, --binary Don't ASCII-armor encode the OpenPGP data +//! -h, --help Prints help information +//! -s, --symmetric Encrypt with a password (can be given multiple times) +//! --use-expired-subkey If a certificate has only expired encryption-capable subkeys, fall back to using the one +//! that expired last +//! -V, --version Prints version information //! //! OPTIONS: //! --compression diff --git a/sq/src/sq.rs b/sq/src/sq.rs index 970e2ebe..f93c0370 100644 --- a/sq/src/sq.rs +++ b/sq/src/sq.rs @@ -279,7 +279,9 @@ fn main() -> Result<()> { &recipients, additional_secrets, mode, m.value_of("compression").expect("has default"), - time.into())?; + time.into(), + m.is_present("use-expired-subkey"), + )?; }, ("sign", Some(m)) => { let mut input = open_or_stdin(m.value_of("input"))?; diff --git a/sq/src/sq_cli.rs b/sq/src/sq_cli.rs index 464d78b4..76164989 100644 --- a/sq/src/sq_cli.rs +++ b/sq/src/sq_cli.rs @@ -145,6 +145,11 @@ pub fn build() -> App<'static, 'static> { .short("t") .help("Chooses keys valid at the specified time and \ sets the signature's creation time")) + .arg(Arg::with_name("use-expired-subkey") + .long("use-expired-subkey") + .help("If a certificate has only expired \ + encryption-capable subkeys, fall back \ + to using the one that expired last")) ) .subcommand(SubCommand::with_name("sign") -- cgit v1.2.3