From 3dc2d24bc3920d0216ff7f19e01e4e073a292a24 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Fri, 17 Jan 2020 16:01:33 +0100 Subject: tool: Add an option to specify the signing time. - Add the option `--time` to the `sign` and `encrypt` subcommands to allow the user to set the signature's creation time. - Use the value of this option to select the signing keys. --- tool/src/commands/mod.rs | 14 +++++--- tool/src/commands/sign.rs | 23 ++++++++---- tool/src/sq-usage.rs | 4 +++ tool/src/sq.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++-- tool/src/sq_cli.rs | 15 ++++++-- 5 files changed, 132 insertions(+), 16 deletions(-) (limited to 'tool') diff --git a/tool/src/commands/mod.rs b/tool/src/commands/mod.rs index 1dc7b908..5b640496 100644 --- a/tool/src/commands/mod.rs +++ b/tool/src/commands/mod.rs @@ -3,6 +3,7 @@ use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::fs::File; use std::io::{self, Write}; +use std::time::SystemTime; use rpassword; extern crate sequoia_openpgp as openpgp; @@ -43,12 +44,12 @@ pub use self::inspect::inspect; pub mod key; /// Returns suitable signing keys from a given list of Certs. -fn get_signing_keys(certs: &[openpgp::Cert]) +fn get_signing_keys(certs: &[openpgp::Cert], timestamp: Option) -> Result> { let mut keys = Vec::new(); 'next_cert: for tsk in certs { - for key in tsk.keys().policy(None).alive().revoked(false) + for key in tsk.keys().policy(timestamp).alive().revoked(false) .for_signing() .map(|ka| ka.key()) { @@ -81,8 +82,8 @@ pub fn encrypt(mapping: &mut store::Mapping, input: &mut dyn io::Read, output: &mut dyn io::Write, npasswords: usize, recipients: Vec<&str>, mut certs: Vec, signers: Vec, - mode: openpgp::types::KeyFlags, - compression: &str) + mode: openpgp::types::KeyFlags, compression: &str, + time: Option) -> Result<()> { for r in recipients { certs.push(mapping.lookup(r).context("No such key found")?.cert()?); @@ -103,7 +104,7 @@ pub fn encrypt(mapping: &mut store::Mapping, "Neither recipient nor password given")); } - let mut signers = get_signing_keys(&signers)?; + let mut signers = get_signing_keys(&signers, time)?; // Build a vector of references to hand to Signer. let recipients: Vec<&openpgp::Cert> = certs.iter().collect(); @@ -160,6 +161,9 @@ pub fn encrypt(mapping: &mut store::Mapping, let mut signer = Signer::new(sink, signers.pop().unwrap()); for s in signers { signer = signer.add_signer(s); + if let Some(time) = time { + signer = signer.creation_time(time); + } } for r in recipients { signer = signer.add_intended_recipient(r); diff --git a/tool/src/commands/sign.rs b/tool/src/commands/sign.rs index a2303fba..673c1e51 100644 --- a/tool/src/commands/sign.rs +++ b/tool/src/commands/sign.rs @@ -2,6 +2,7 @@ use failure::{self, ResultExt}; use std::fs; use std::io; use std::path::PathBuf; +use std::time::SystemTime; use tempfile::NamedTempFile; extern crate sequoia_openpgp as openpgp; @@ -20,20 +21,22 @@ use crate::create_or_stdout; pub fn sign(input: &mut dyn io::Read, output_path: Option<&str>, secrets: Vec, detached: bool, binary: bool, - append: bool, notarize: bool, force: bool) + append: bool, notarize: bool, time: Option, + force: bool) -> Result<()> { match (detached, append|notarize) { (_, false) | (true, true) => sign_data(input, output_path, secrets, detached, binary, append, - force), + time, force), (false, true) => - sign_message(input, output_path, secrets, binary, notarize, force), + sign_message(input, output_path, secrets, binary, notarize, + time, force), } } fn sign_data(input: &mut dyn io::Read, output_path: Option<&str>, secrets: Vec, detached: bool, binary: bool, - append: bool, force: bool) + append: bool, time: Option, force: bool) -> Result<()> { let (mut output, prepend_sigs, tmp_path): (Box, Vec, Option) = @@ -80,7 +83,7 @@ fn sign_data(input: &mut dyn io::Read, output_path: Option<&str>, output }; - let mut keypairs = super::get_signing_keys(&secrets)?; + let mut keypairs = super::get_signing_keys(&secrets, time)?; if keypairs.is_empty() { return Err(failure::format_err!("No signing keys found")); } @@ -97,6 +100,9 @@ fn sign_data(input: &mut dyn io::Read, output_path: Option<&str>, let mut signer = Signer::new(sink, keypairs.pop().unwrap()); for s in keypairs { signer = signer.add_signer(s); + if let Some(time) = time { + signer = signer.creation_time(time); + } } if detached { signer = signer.detached(); @@ -130,7 +136,7 @@ fn sign_data(input: &mut dyn io::Read, output_path: Option<&str>, fn sign_message(input: &mut dyn io::Read, output_path: Option<&str>, secrets: Vec, binary: bool, notarize: bool, - force: bool) + time: Option, force: bool) -> Result<()> { let mut output = create_or_stdout(output_path, force)?; let output = if ! binary { @@ -141,7 +147,7 @@ fn sign_message(input: &mut dyn io::Read, output_path: Option<&str>, output }; - let mut keypairs = super::get_signing_keys(&secrets)?; + let mut keypairs = super::get_signing_keys(&secrets, time)?; if keypairs.is_empty() { return Err(failure::format_err!("No signing keys found")); } @@ -213,6 +219,9 @@ fn sign_message(input: &mut dyn io::Read, output_path: Option<&str>, let mut signer = Signer::new(sink, keypairs.pop().unwrap()); for s in keypairs.drain(..) { signer = signer.add_signer(s); + if let Some(time) = time { + signer = signer.creation_time(time); + } } sink = signer.build().context("Failed to create signer")?; state = State::Signing { signature_count: 0, }; diff --git a/tool/src/sq-usage.rs b/tool/src/sq-usage.rs index be4b3695..d09e8e86 100644 --- a/tool/src/sq-usage.rs +++ b/tool/src/sq-usage.rs @@ -87,6 +87,8 @@ //! -r, --recipient