diff options
author | Wiktor Kwapisiewicz <wiktor@metacode.biz> | 2021-10-18 10:22:46 +0200 |
---|---|---|
committer | Wiktor Kwapisiewicz <wiktor@metacode.biz> | 2021-11-03 10:09:24 +0100 |
commit | ac08b36fd92a77adaa805f8464ed9556c2af2845 (patch) | |
tree | c3f9296b86ab8f11a8e3a8d1a533e41be250a49c /sq | |
parent | 4b887a8cea6d7893b98874d4e4ff29e2ebe76543 (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.
Diffstat (limited to 'sq')
-rw-r--r-- | sq/src/commands/decrypt.rs | 9 | ||||
-rw-r--r-- | sq/src/commands/mod.rs | 58 | ||||
-rw-r--r-- | sq/src/commands/sign.rs | 86 | ||||
-rw-r--r-- | sq/src/sq-usage.rs | 12 | ||||
-rw-r--r-- | sq/src/sq.rs | 43 | ||||
-rw-r--r-- | sq/src/sq_cli.rs | 12 |
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, ¬ations)?; } else { - commands::sign(config, &mut input, output, secrets, detached, - binary, append, notarize, time, ¬ations)?; + commands::sign(commands::sign::SignOpts { + config, + private_key_store, + input: &mut input, + output_path: output, + secrets, + detached, + binary, + append, + notarize, + time, + notations: ¬ations + })?; } }, ("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")) |