summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Runge <dave@sleepmap.de>2022-12-16 14:27:16 +0100
committerDavid Runge <dave@sleepmap.de>2022-12-16 16:43:32 +0100
commite1edd66a1b227f9ee487418af689986749a0c5f9 (patch)
tree600a6ccf3f26696e5d42acf23efa8c82dbf23fcb
parente1aca9374c184936137babccea0100ed7bf47656 (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.md2
-rw-r--r--sq/sq-usage.md12
-rw-r--r--sq/src/commands/inspect.rs74
-rw-r--r--sq/src/sq_cli/inspect.rs17
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>,
}