summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWiktor Kwapisiewicz <wiktor@metacode.biz>2021-10-18 10:22:46 +0200
committerWiktor Kwapisiewicz <wiktor@metacode.biz>2021-11-03 10:09:24 +0100
commitac08b36fd92a77adaa805f8464ed9556c2af2845 (patch)
treec3f9296b86ab8f11a8e3a8d1a533e41be250a49c
parent4b887a8cea6d7893b98874d4e4ff29e2ebe76543 (diff)
sq: Add parameter for specifying private key store
- Extend the decrypt and sign operations with private-key-store parameter. - Reduce the number of parameters by using wrapper structs.
-rw-r--r--sq/src/commands/decrypt.rs9
-rw-r--r--sq/src/commands/mod.rs58
-rw-r--r--sq/src/commands/sign.rs86
-rw-r--r--sq/src/sq-usage.rs12
-rw-r--r--sq/src/sq.rs43
-rw-r--r--sq/src/sq_cli.rs12
6 files changed, 141 insertions, 79 deletions
diff --git a/sq/src/commands/decrypt.rs b/sq/src/commands/decrypt.rs
index 6903b8f9..fc66c8ed 100644
--- a/sq/src/commands/decrypt.rs
+++ b/sq/src/commands/decrypt.rs
@@ -37,7 +37,7 @@ struct Helper<'a> {
}
impl<'a> Helper<'a> {
- fn new(config: &Config<'a>,
+ fn new(config: &Config<'a>, _private_key_store: Option<&str>,
signatures: usize, certs: Vec<Cert>, secrets: Vec<Cert>,
dump_session_key: bool, dump: bool)
-> Self
@@ -276,14 +276,15 @@ impl<'a> DecryptionHelper for Helper<'a> {
}
pub fn decrypt(config: Config,
+ private_key_store: Option<&str>,
input: &mut (dyn io::Read + Sync + Send),
output: &mut dyn io::Write,
signatures: usize, certs: Vec<Cert>, secrets: Vec<Cert>,
dump_session_key: bool,
dump: bool, hex: bool)
-> Result<()> {
- let helper = Helper::new(&config, signatures, certs, secrets,
- dump_session_key, dump || hex);
+ let helper = Helper::new(&config, private_key_store, signatures, certs,
+ secrets, dump_session_key, dump || hex);
let mut decryptor = DecryptorBuilder::from_reader(input)?
.mapping(hex)
.with_policy(&config.policy, None, helper)
@@ -305,7 +306,7 @@ pub fn decrypt_unwrap(config: Config,
secrets: Vec<Cert>, dump_session_key: bool)
-> Result<()>
{
- let mut helper = Helper::new(&config, 0, Vec::new(), secrets,
+ let mut helper = Helper::new(&config, None, 0, Vec::new(), secrets,
dump_session_key, false);
let mut ppr = PacketParser::from_reader(input)?;
diff --git a/sq/src/commands/mod.rs b/sq/src/commands/mod.rs
index c6d2c54a..001e9cea 100644
--- a/sq/src/commands/mod.rs
+++ b/sq/src/commands/mod.rs
@@ -54,6 +54,7 @@ pub mod certify;
/// Returns suitable signing keys from a given list of Certs.
#[allow(clippy::never_loop)]
fn get_signing_keys(certs: &[openpgp::Cert], p: &dyn Policy,
+ _private_key_store: Option<&str>,
timestamp: Option<SystemTime>)
-> Result<Vec<crypto::KeyPair>>
{
@@ -90,47 +91,54 @@ fn get_signing_keys(certs: &[openpgp::Cert], p: &dyn Policy,
Ok(keys)
}
-pub fn encrypt<'a>(policy: &'a dyn Policy,
- input: &mut dyn io::Read, message: Message<'a>,
- npasswords: usize, recipients: &'a [openpgp::Cert],
- signers: Vec<openpgp::Cert>,
- mode: openpgp::types::KeyFlags, compression: &str,
- time: Option<SystemTime>,
- use_expired_subkey: bool,
-)
- -> Result<()> {
- let mut passwords: Vec<crypto::Password> = Vec::with_capacity(npasswords);
- for n in 0..npasswords {
+pub struct EncryptOpts<'a> {
+ pub policy: &'a dyn Policy,
+ pub private_key_store: Option<&'a str>,
+ pub input: &'a mut dyn io::Read,
+ pub message: Message<'a>,
+ pub npasswords: usize,
+ pub recipients: &'a [openpgp::Cert],
+ pub signers: Vec<openpgp::Cert>,
+ pub mode: openpgp::types::KeyFlags,
+ pub compression: &'a str,
+ pub time: Option<SystemTime>,
+ pub use_expired_subkey: bool,
+}
+
+pub fn encrypt(opts: EncryptOpts) -> Result<()> {
+ let mut passwords: Vec<crypto::Password> = Vec::with_capacity(opts.npasswords);
+ for n in 0..opts.npasswords {
let nprompt = format!("Enter password {}: ", n + 1);
passwords.push(rpassword::read_password_from_tty(Some(
- if npasswords > 1 {
+ if opts.npasswords > 1 {
&nprompt
} else {
"Enter password: "
}))?.into());
}
- if recipients.len() + passwords.len() == 0 {
+ if opts.recipients.len() + passwords.len() == 0 {
return Err(anyhow::anyhow!(
"Neither recipient nor password given"));
}
- let mut signers = get_signing_keys(&signers, policy, time)?;
+ let mut signers = get_signing_keys(&opts.signers, opts.policy,
+ opts.private_key_store, opts.time)?;
// Build a vector of recipients to hand to Encryptor.
let mut recipient_subkeys: Vec<Recipient> = Vec::new();
- for cert in recipients.iter() {
+ for cert in opts.recipients.iter() {
let mut count = 0;
- for key in cert.keys().with_policy(policy, None).alive().revoked(false)
- .key_flags(&mode).supported().map(|ka| ka.key())
+ for key in cert.keys().with_policy(opts.policy, None).alive().revoked(false)
+ .key_flags(&opts.mode).supported().map(|ka| ka.key())
{
recipient_subkeys.push(key.into());
count += 1;
}
if count == 0 {
let mut expired_keys = Vec::new();
- for ka in cert.keys().with_policy(policy, None).revoked(false)
- .key_flags(&mode).supported()
+ for ka in cert.keys().with_policy(opts.policy, None).revoked(false)
+ .key_flags(&opts.mode).supported()
{
let key = ka.key();
expired_keys.push(
@@ -141,7 +149,7 @@ pub fn encrypt<'a>(policy: &'a dyn Policy,
expired_keys.sort_by_key(|(expiration_time, _)| *expiration_time);
if let Some((expiration_time, key)) = expired_keys.last() {
- if use_expired_subkey {
+ if opts.use_expired_subkey {
recipient_subkeys.push((*key).into());
} else {
use chrono::{DateTime, offset::Utc};
@@ -161,13 +169,13 @@ pub fn encrypt<'a>(policy: &'a dyn Policy,
// We want to encrypt a literal data packet.
let encryptor =
- Encryptor::for_recipients(message, recipient_subkeys)
+ Encryptor::for_recipients(opts.message, recipient_subkeys)
.add_passwords(passwords);
let mut sink = encryptor.build()
.context("Failed to create encryptor")?;
- match compression {
+ match opts.compression {
"none" => (),
"pad" => sink = Padder::new(sink).build()?,
"zip" => sink =
@@ -184,11 +192,11 @@ pub fn encrypt<'a>(policy: &'a dyn Policy,
let mut signer = Signer::new(sink, signers.pop().unwrap());
for s in signers {
signer = signer.add_signer(s);
- if let Some(time) = time {
+ if let Some(time) = opts.time {
signer = signer.creation_time(time);
}
}
- for r in recipients.iter() {
+ for r in opts.recipients.iter() {
signer = signer.add_intended_recipient(r);
}
sink = signer.build()?;
@@ -198,7 +206,7 @@ pub fn encrypt<'a>(policy: &'a dyn Policy,
.context("Failed to create literal writer")?;
// Finally, copy stdin to our writer stack to encrypt the data.
- io::copy(input, &mut literal_writer)
+ io::copy(opts.input, &mut literal_writer)
.context("Failed to encrypt")?;
literal_writer.finalize()
diff --git a/sq/src/commands/sign.rs b/sq/src/commands/sign.rs
index a373910c..ff81846f 100644
--- a/sq/src/commands/sign.rs
+++ b/sq/src/commands/sign.rs
@@ -23,29 +23,41 @@ use crate::{
Config,
};
-pub fn sign(config: Config,
- input: &mut (dyn io::Read + Sync + Send),
- output_path: Option<&str>,
- secrets: Vec<openpgp::Cert>, detached: bool, binary: bool,
- append: bool, notarize: bool, time: Option<SystemTime>,
- notations: &[(bool, NotationData)])
- -> Result<()> {
- match (detached, append|notarize) {
+pub struct SignOpts<'a> {
+ pub config: Config<'a>,
+ pub private_key_store: Option<&'a str>,
+ pub input: &'a mut (dyn io::Read + Sync + Send),
+ pub output_path: Option<&'a str>,
+ pub secrets: Vec<openpgp::Cert>,
+ pub detached: bool,
+ pub binary: bool,
+ pub append: bool,
+ pub notarize: bool,
+ pub time: Option<SystemTime>,
+ pub notations: &'a [(bool, NotationData)]
+}
+
+pub fn sign(opts: SignOpts) -> Result<()> {
+ match (opts.detached, opts.append|opts.notarize) {
(_, false) | (true, true) =>
- sign_data(config, input, output_path, secrets, detached, binary,
- append, time, notations),
+ sign_data(opts),
(false, true) =>
- sign_message(config, input, output_path, secrets, binary, notarize,
- time, notations),
+ sign_message(opts),
}
}
-fn sign_data(config: Config,
- input: &mut dyn io::Read, output_path: Option<&str>,
- secrets: Vec<openpgp::Cert>, detached: bool, binary: bool,
- append: bool, time: Option<SystemTime>,
- notations: &[(bool, NotationData)])
- -> Result<()> {
+fn sign_data(opts: SignOpts) -> Result<()> {
+ let SignOpts {
+ config,
+ private_key_store,
+ input,
+ output_path,
+ secrets,
+ detached,
+ binary,
+ append,
+ time,
+ notations, ..} = opts;
let (mut output, prepend_sigs, tmp_path):
(Box<dyn io::Write + Sync + Send>, Vec<Signature>, Option<PathBuf>) =
if detached && append && output_path.is_some() {
@@ -79,7 +91,7 @@ fn sign_data(config: Config,
(config.create_or_stdout_safe(output_path)?, Vec::new(), None)
};
- let mut keypairs = super::get_signing_keys(&secrets, &config.policy, time)?;
+ let mut keypairs = super::get_signing_keys(&secrets, &config.policy, private_key_store, time)?;
if keypairs.is_empty() {
return Err(anyhow::anyhow!("No signing keys found"));
}
@@ -151,31 +163,28 @@ fn sign_data(config: Config,
Ok(())
}
-fn sign_message(config: Config,
- input: &mut (dyn io::Read + Sync + Send),
- output_path: Option<&str>,
- secrets: Vec<openpgp::Cert>, binary: bool, notarize: bool,
- time: Option<SystemTime>,
- notations: &[(bool, NotationData)])
- -> Result<()> {
+fn sign_message(opts: SignOpts) -> Result<()> {
let mut output =
- config.create_or_stdout_pgp(output_path,
- binary,
+ opts.config.create_or_stdout_pgp(opts.output_path,
+ opts.binary,
armor::Kind::Message)?;
- sign_message_(config, input, &mut output, secrets, notarize, time, notations)?;
+ sign_message_(opts, &mut output)?;
output.finalize()?;
Ok(())
}
-fn sign_message_(config: Config,
- input: &mut (dyn io::Read + Sync + Send),
- output: &mut (dyn io::Write + Sync + Send),
- secrets: Vec<openpgp::Cert>, notarize: bool,
- time: Option<SystemTime>,
- notations: &[(bool, NotationData)])
- -> Result<()>
+fn sign_message_(opts: SignOpts, output: &mut (dyn io::Write + Sync + Send)) -> Result<()>
{
- let mut keypairs = super::get_signing_keys(&secrets, &config.policy, time)?;
+ let SignOpts {
+ config,
+ private_key_store,
+ input,
+ secrets,
+ notarize,
+ time,
+ notations, ..
+ } = opts;
+ let mut keypairs = super::get_signing_keys(&secrets, &config.policy, private_key_store, time)?;
if keypairs.is_empty() {
return Err(anyhow::anyhow!("No signing keys found"));
}
@@ -373,6 +382,7 @@ fn sign_message_(config: Config,
}
pub fn clearsign(config: Config,
+ private_key_store: Option<&str>,
mut input: impl io::Read + Sync + Send,
mut output: impl io::Write + Sync + Send,
secrets: Vec<openpgp::Cert>,
@@ -380,7 +390,7 @@ pub fn clearsign(config: Config,
notations: &[(bool, NotationData)])
-> Result<()>
{
- let mut keypairs = super::get_signing_keys(&secrets, &config.policy, time)?;
+ let mut keypairs = super::get_signing_keys(&secrets, &config.policy, private_key_store, time)?;
if keypairs.is_empty() {
return Err(anyhow::anyhow!("No signing keys found"));
}
diff --git a/sq/src/sq-usage.rs b/sq/src/sq-usage.rs
index 54da6705..3fed5e03 100644
--- a/sq/src/sq-usage.rs
+++ b/sq/src/sq-usage.rs
@@ -95,6 +95,9 @@
//! -o, --output <FILE>
//! Writes to FILE or stdout if omitted
//!
+//! --private-key-store <KEY_STORE>
+//! Provides parameters for private key store
+//!
//! --recipient-cert <CERT-RING>...
//! Encrypts for all recipients in CERT-RING
//!
@@ -166,6 +169,9 @@
//! -o, --output <FILE>
//! Writes to FILE or stdout if omitted
//!
+//! --private-key-store <KEY_STORE>
+//! Provides parameters for private key store
+//!
//! --recipient-key <KEY>...
//! Decrypts with KEY
//!
@@ -241,6 +247,9 @@
//! -o, --output <FILE>
//! Writes to FILE or stdout if omitted
//!
+//! --private-key-store <KEY_STORE>
+//! Provides parameters for private key store
+//!
//! --signer-key <KEY>...
//! Signs using KEY
//!
@@ -1505,6 +1514,9 @@
//! -o, --output <FILE>
//! Writes to FILE or stdout if omitted
//!
+//! --private-key-store <KEY_STORE>
+//! Provides parameters for private key store
+//!
//! --recipient-key <KEY>...
//! Decrypts the message with KEY
//!
diff --git a/sq/src/sq.rs b/sq/src/sq.rs
index d9a22b74..d49f340a 100644
--- a/sq/src/sq.rs
+++ b/sq/src/sq.rs
@@ -433,7 +433,8 @@ fn main() -> Result<()> {
let secrets = m.values_of("secret-key-file")
.map(load_keys)
.unwrap_or_else(|| Ok(vec![]))?;
- commands::decrypt(config,
+ let private_key_store = m.value_of("private-key-store");
+ commands::decrypt(config, private_key_store,
&mut input, &mut output,
signatures, certs, secrets,
m.is_present("dump-session-key"),
@@ -468,14 +469,20 @@ fn main() -> Result<()> {
} else {
None
};
- commands::encrypt(policy, &mut input, output,
- m.occurrences_of("symmetric") as usize,
- &recipients, additional_secrets,
- mode,
- m.value_of("compression").expect("has default"),
- time,
- m.is_present("use-expired-subkey"),
- )?;
+ let private_key_store = m.value_of("private-key-store");
+ commands::encrypt(commands::EncryptOpts {
+ policy,
+ private_key_store,
+ input: &mut input,
+ message: output,
+ npasswords: m.occurrences_of("symmetric") as usize,
+ recipients: &recipients,
+ signers: additional_secrets,
+ mode,
+ compression: m.value_of("compression").expect("has default"),
+ time,
+ use_expired_subkey: m.is_present("use-expired-subkey"),
+ })?;
},
("sign", Some(m)) => {
let mut input = open_or_stdin(m.value_of("input"))?;
@@ -484,6 +491,7 @@ fn main() -> Result<()> {
let binary = m.is_present("binary");
let append = m.is_present("append");
let notarize = m.is_present("notarize");
+ let private_key_store = m.value_of("private-key-store");
let secrets = m.values_of("secret-key-file")
.map(load_keys)
.unwrap_or_else(|| Ok(vec![]))?;
@@ -524,11 +532,22 @@ fn main() -> Result<()> {
commands::merge_signatures(&mut input, &mut input2, output)?;
} else if m.is_present("clearsign") {
let output = config.create_or_stdout_safe(output)?;
- commands::sign::clearsign(config, input, output, secrets,
+ commands::sign::clearsign(config, private_key_store, input, output, secrets,
time, &notations)?;
} else {
- commands::sign(config, &mut input, output, secrets, detached,
- binary, append, notarize, time, &notations)?;
+ commands::sign(commands::sign::SignOpts {
+ config,
+ private_key_store,
+ input: &mut input,
+ output_path: output,
+ secrets,
+ detached,
+ binary,
+ append,
+ notarize,
+ time,
+ notations: &notations
+ })?;
}
},
("verify", Some(m)) => {
diff --git a/sq/src/sq_cli.rs b/sq/src/sq_cli.rs
index b0ce93d7..d8198f6f 100644
--- a/sq/src/sq_cli.rs
+++ b/sq/src/sq_cli.rs
@@ -124,6 +124,9 @@ $ sq decrypt ciphertext.pgp
.long("recipient-key").value_name("KEY")
.multiple(true).number_of_values(1)
.help("Decrypts with KEY"))
+ .arg(Arg::with_name("private-key-store")
+ .long("private-key-store").value_name("KEY_STORE")
+ .help("Provides parameters for private key store"))
.arg(Arg::with_name("dump-session-key")
.long("dump-session-key")
.help("Prints the session key to stderr"))
@@ -175,6 +178,9 @@ $ sq encrypt --symmetric message.txt
.long("signer-key").value_name("KEY")
.multiple(true).number_of_values(1)
.help("Signs the message with KEY"))
+ .arg(Arg::with_name("private-key-store")
+ .long("private-key-store").value_name("KEY_STORE")
+ .help("Provides parameters for private key store"))
.arg(Arg::with_name("symmetric")
.short("s").long("symmetric")
.multiple(true)
@@ -244,6 +250,9 @@ $ sq sign --detached --signer-key juliet.pgp message.txt
.arg(Arg::with_name("binary")
.short("B").long("binary")
.help("Emits binary data"))
+ .arg(Arg::with_name("private-key-store")
+ .long("private-key-store").value_name("KEY_STORE")
+ .help("Provides parameters for private key store"))
.arg(Arg::with_name("detached")
.long("detached")
.help("Creates a detached signature"))
@@ -1211,6 +1220,9 @@ $ sq packet decrypt --recipient-key juliet.pgp ciphertext.pgp
.long("recipient-key").value_name("KEY")
.multiple(true).number_of_values(1)
.help("Decrypts the message with KEY"))
+ .arg(Arg::with_name("private-key-store")
+ .long("private-key-store").value_name("KEY_STORE")
+ .help("Provides parameters for private key store"))
.arg(Arg::with_name("dump-session-key")
.long("dump-session-key")
.help("Prints the session key to stderr"))