diff options
author | David Runge <dave@sleepmap.de> | 2022-12-16 14:27:16 +0100 |
---|---|---|
committer | David Runge <dave@sleepmap.de> | 2022-12-16 16:43:32 +0100 |
commit | e1edd66a1b227f9ee487418af689986749a0c5f9 (patch) | |
tree | 600a6ccf3f26696e5d42acf23efa8c82dbf23fcb | |
parent | e1aca9374c184936137babccea0100ed7bf47656 (diff) |
sq: Add --time option to sq inspect
- The `sq inspect` command now understands a `--time` option, with
which an ISO 8601 formatted string can be provided to inspect a
certificate at a given time. If the option is not provided, the
certificate is inspected "now" (default behavior).
- Change subplot scenario "Generate a key that expires at a given
moment" to also check the generated key is expired by checking
against the output of `sq inspect --time` at a date after the
expiration date.
- Fixes #809
-rw-r--r-- | sq/sq-subplot.md | 2 | ||||
-rw-r--r-- | sq/sq-usage.md | 12 | ||||
-rw-r--r-- | sq/src/commands/inspect.rs | 74 | ||||
-rw-r--r-- | sq/src/sq_cli/inspect.rs | 17 |
4 files changed, 85 insertions, 20 deletions
diff --git a/sq/sq-subplot.md b/sq/sq-subplot.md index 4b32f156..04b56cdd 100644 --- a/sq/sq-subplot.md +++ b/sq/sq-subplot.md @@ -433,6 +433,8 @@ given an installed sq when I run sq key generate --export key.pgp --expires=2038-01-19T03:14:07+00:00 when I run sq inspect key.pgp then stdout contains "Expiration time: 2038-01-19 03:14" +when I run sq inspect --time 2038-01-20T00:00:00+00:00 key.pgp +then stdout contains "Invalid: The primary key is not live" ~~~ ### Generate a key with a given duration diff --git a/sq/sq-usage.md b/sq/sq-usage.md index 3f07bcaa..5d39f2ea 100644 --- a/sq/sq-usage.md +++ b/sq/sq-usage.md @@ -1650,6 +1650,18 @@ OPTIONS: -h, --help Print help information + --time <TIME> + Sets the certification time to TIME. TIME is interpreted as an ISO + 8601 timestamp. To set the certification time to July 21, 2013 at + midnight UTC, you can do: + + $ sq inspect --time 20130721 cert.pgp + + To include a time, add a T, the time and optionally the timezone + (the default timezone is UTC): + + $ sq inspect --time 20130721T0550+0200 cert.pgp + EXAMPLES: # Inspects a certificate diff --git a/sq/src/commands/inspect.rs b/sq/src/commands/inspect.rs index 6da46a9d..966c9959 100644 --- a/sq/src/commands/inspect.rs +++ b/sq/src/commands/inspect.rs @@ -1,5 +1,8 @@ use std::convert::TryFrom; use std::io::{self, Read}; +use std::time::SystemTime; + +use anyhow::Context; use sequoia_openpgp as openpgp; use openpgp::{KeyHandle, Packet, Result}; @@ -23,6 +26,16 @@ pub fn inspect(c: inspect::Command, policy: &dyn Policy, output: &mut dyn io::Wr -> Result<()> { let print_certifications = c.certifications; + let time = if let Some(t) = c.time { + let time = SystemTime::from( + crate::parse_iso8601(&t, chrono::NaiveTime::from_hms(0, 0, 0)) + .context(format!("Parsing --time {}", t))?, + ); + Some(time) + } else { + None + }; + let input = c.input.as_deref(); let input_name = input.unwrap_or("-"); write!(output, "{}: ", input_name)?; @@ -51,8 +64,13 @@ pub fn inspect(c: inspect::Command, policy: &dyn Policy, output: &mut dyn io::Wr let pp = openpgp::PacketPile::from( std::mem::take(&mut packets)); let cert = openpgp::Cert::try_from(pp)?; - inspect_cert(policy, output, &cert, - print_certifications)?; + inspect_cert( + policy, + time, + output, + &cert, + print_certifications, + )?; } }, Packet::Literal(_) => { @@ -110,8 +128,7 @@ pub fn inspect(c: inspect::Command, policy: &dyn Policy, output: &mut dyn io::Wr } else if is_cert.is_ok() || is_keyring.is_ok() { let pp = openpgp::PacketPile::from(packets); let cert = openpgp::Cert::try_from(pp)?; - inspect_cert(policy, output, &cert, - print_certifications)?; + inspect_cert(policy, time, output, &cert, print_certifications)?; } else if packets.is_empty() && ! sigs.is_empty() { writeln!(output, "Detached signature{}.", if sigs.len() > 1 { "s" } else { "" })?; @@ -134,9 +151,13 @@ pub fn inspect(c: inspect::Command, policy: &dyn Policy, output: &mut dyn io::Wr Ok(()) } -fn inspect_cert(policy: &dyn Policy, - output: &mut dyn io::Write, cert: &openpgp::Cert, - print_certifications: bool) -> Result<()> { +fn inspect_cert( + policy: &dyn Policy, + time: Option<SystemTime>, + output: &mut dyn io::Write, + cert: &openpgp::Cert, + print_certifications: bool, +) -> Result<()> { if cert.is_tsk() { writeln!(output, "Transferable Secret Key.")?; } else { @@ -145,15 +166,27 @@ fn inspect_cert(policy: &dyn Policy, writeln!(output)?; writeln!(output, " Fingerprint: {}", cert.fingerprint())?; inspect_revocation(output, "", cert.revocation_status(policy, None))?; - inspect_key(policy, output, "", cert.keys().next().unwrap(), - print_certifications)?; + inspect_key( + policy, + time, + output, + "", + cert.keys().next().unwrap(), + print_certifications, + )?; writeln!(output)?; - for vka in cert.keys().subkeys().with_policy(policy, None) { + for vka in cert.keys().subkeys().with_policy(policy, time) { writeln!(output, " Subkey: {}", vka.key().fingerprint())?; inspect_revocation(output, "", vka.revocation_status())?; - inspect_key(policy, output, "", vka.into_key_amalgamation().into(), - print_certifications)?; + inspect_key( + policy, + time, + output, + "", + vka.into_key_amalgamation().into(), + print_certifications, + )?; writeln!(output)?; } @@ -224,16 +257,17 @@ fn inspect_cert(policy: &dyn Policy, Ok(()) } -fn inspect_key(policy: &dyn Policy, - output: &mut dyn io::Write, - indent: &str, - ka: ErasedKeyAmalgamation<PublicParts>, - print_certifications: bool) - -> Result<()> -{ +fn inspect_key( + policy: &dyn Policy, + time: Option<SystemTime>, + output: &mut dyn io::Write, + indent: &str, + ka: ErasedKeyAmalgamation<PublicParts>, + print_certifications: bool, +) -> Result<()> { let key = ka.key(); let bundle = ka.bundle(); - let vka = match ka.with_policy(policy, None) { + let vka = match ka.with_policy(policy, time) { Ok(vka) => { if let Err(e) = vka.alive() { writeln!(output, "{} Invalid: {}", indent, e)?; diff --git a/sq/src/sq_cli/inspect.rs b/sq/src/sq_cli/inspect.rs index af9e29ac..e8e7841a 100644 --- a/sq/src/sq_cli/inspect.rs +++ b/sq/src/sq_cli/inspect.rs @@ -39,5 +39,22 @@ pub struct Command { help = "Prints third-party certifications", )] pub certifications: bool, + #[clap( + long = "time", + value_name = "TIME", + help = "Sets the certification time to TIME (as ISO 8601)", + long_help = "\ +Sets the certification time to TIME. TIME is interpreted as an ISO 8601 \ +timestamp. To set the certification time to July 21, 2013 at midnight UTC, \ +you can do: + +$ sq inspect --time 20130721 cert.pgp +To include a time, add a T, the time and optionally the timezone (the \ +default timezone is UTC): + +$ sq inspect --time 20130721T0550+0200 cert.pgp +" + )] + pub time: Option<String>, } |