Use cert designators for the signer arguments of sq encrypt
.
- Fixes #429.
This commit is contained in:
parent
359245db14
commit
cc244afd79
@ -1,12 +1,7 @@
|
|||||||
//! Command-line parser for `sq encrypt`.
|
//! Command-line parser for `sq encrypt`.
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use clap::{ValueEnum, Parser};
|
use clap::{ValueEnum, Parser};
|
||||||
|
|
||||||
use sequoia_openpgp as openpgp;
|
|
||||||
use openpgp::KeyHandle;
|
|
||||||
|
|
||||||
use super::types::ClapData;
|
use super::types::ClapData;
|
||||||
use super::types::EncryptPurpose;
|
use super::types::EncryptPurpose;
|
||||||
use super::types::MetadataTime;
|
use super::types::MetadataTime;
|
||||||
@ -14,8 +9,7 @@ use super::types::FileOrStdin;
|
|||||||
use super::types::FileOrStdout;
|
use super::types::FileOrStdout;
|
||||||
|
|
||||||
use crate::cli::types::CertDesignators;
|
use crate::cli::types::CertDesignators;
|
||||||
use crate::cli::types::cert_designator::CertUserIDEmailFileWithPasswordArgs;
|
use crate::cli::types::cert_designator::*;
|
||||||
use crate::cli::types::cert_designator::RecipientPrefix;
|
|
||||||
|
|
||||||
use crate::cli::examples;
|
use crate::cli::examples;
|
||||||
use examples::*;
|
use examples::*;
|
||||||
@ -130,18 +124,11 @@ pub struct Command {
|
|||||||
)]
|
)]
|
||||||
pub set_metadata_time: MetadataTime,
|
pub set_metadata_time: MetadataTime,
|
||||||
|
|
||||||
#[clap(
|
#[command(flatten)]
|
||||||
long = "signer-file",
|
pub signers: CertDesignators<CertUserIDEmailFileArgs,
|
||||||
value_name = "KEY_FILE",
|
SignerPrefix,
|
||||||
help = "Sign the message using the key in KEY_FILE",
|
OptionalValue,
|
||||||
)]
|
SignerDoc>,
|
||||||
pub signer_key_file: Vec<PathBuf>,
|
|
||||||
#[clap(
|
|
||||||
long = "signer",
|
|
||||||
value_name = "KEYID|FINGERPRINT",
|
|
||||||
help = "Sign the message using the specified key on the key store",
|
|
||||||
)]
|
|
||||||
pub signer_key: Vec<KeyHandle>,
|
|
||||||
|
|
||||||
#[clap(
|
#[clap(
|
||||||
long = "encrypt-for",
|
long = "encrypt-for",
|
||||||
@ -178,6 +165,24 @@ pub struct Command {
|
|||||||
pub use_expired_subkey: bool,
|
pub use_expired_subkey: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Documentation for signer arguments.
|
||||||
|
pub struct SignerDoc {}
|
||||||
|
impl AdditionalDocs for SignerDoc {
|
||||||
|
fn help(arg: &'static str, help: &'static str) -> clap::builder::StyledStr {
|
||||||
|
match arg {
|
||||||
|
"file" =>
|
||||||
|
"Sign the message using the key read from PATH"
|
||||||
|
.into(),
|
||||||
|
_ => {
|
||||||
|
debug_assert!(help.starts_with("Use certificates"));
|
||||||
|
help.replace("Use certificates",
|
||||||
|
"Sign the message using the key")
|
||||||
|
.into()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(ValueEnum, Debug, Clone)]
|
#[derive(ValueEnum, Debug, Clone)]
|
||||||
pub enum CompressionMode {
|
pub enum CompressionMode {
|
||||||
None,
|
None,
|
||||||
|
@ -10,9 +10,6 @@ use sequoia_openpgp as openpgp;
|
|||||||
use openpgp::armor;
|
use openpgp::armor;
|
||||||
use openpgp::cert::amalgamation::ValidAmalgamation;
|
use openpgp::cert::amalgamation::ValidAmalgamation;
|
||||||
use openpgp::crypto;
|
use openpgp::crypto;
|
||||||
use openpgp::crypto::Password;
|
|
||||||
use openpgp::KeyHandle;
|
|
||||||
use openpgp::KeyID;
|
|
||||||
use openpgp::policy::Policy;
|
use openpgp::policy::Policy;
|
||||||
use openpgp::serialize::stream::Compressor;
|
use openpgp::serialize::stream::Compressor;
|
||||||
use openpgp::serialize::stream::Encryptor2 as Encryptor;
|
use openpgp::serialize::stream::Encryptor2 as Encryptor;
|
||||||
@ -25,8 +22,6 @@ use openpgp::serialize::stream::padding::Padder;
|
|||||||
use openpgp::types::CompressionAlgorithm;
|
use openpgp::types::CompressionAlgorithm;
|
||||||
use openpgp::types::KeyFlags;
|
use openpgp::types::KeyFlags;
|
||||||
|
|
||||||
use sequoia_keystore::Protection;
|
|
||||||
|
|
||||||
use crate::cli;
|
use crate::cli;
|
||||||
use crate::cli::types::EncryptPurpose;
|
use crate::cli::types::EncryptPurpose;
|
||||||
use crate::cli::types::FileOrStdin;
|
use crate::cli::types::FileOrStdin;
|
||||||
@ -34,7 +29,6 @@ use crate::cli::types::MetadataTime;
|
|||||||
use crate::Sq;
|
use crate::Sq;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::common::password;
|
use crate::common::password;
|
||||||
use crate::load_certs;
|
|
||||||
use crate::print_error_chain;
|
use crate::print_error_chain;
|
||||||
|
|
||||||
use crate::commands::CompressionMode;
|
use crate::commands::CompressionMode;
|
||||||
@ -58,9 +52,10 @@ pub fn dispatch(sq: Sq, command: cli::encrypt::Command) -> Result<()> {
|
|||||||
armor::Kind::Message,
|
armor::Kind::Message,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let additional_secrets =
|
let signers =
|
||||||
load_certs(command.signer_key_file.iter())?;
|
sq.resolve_certs_or_fail(&command.signers,
|
||||||
let signer_keys = &command.signer_key[..];
|
sequoia_wot::FULLY_TRUSTED)?;
|
||||||
|
let signers = sq.get_signing_keys(&signers, None)?;
|
||||||
|
|
||||||
encrypt(
|
encrypt(
|
||||||
&sq,
|
&sq,
|
||||||
@ -70,8 +65,7 @@ pub fn dispatch(sq: Sq, command: cli::encrypt::Command) -> Result<()> {
|
|||||||
command.recipients.with_passwords(),
|
command.recipients.with_passwords(),
|
||||||
command.recipients.with_password_files(),
|
command.recipients.with_password_files(),
|
||||||
&recipients,
|
&recipients,
|
||||||
additional_secrets,
|
signers,
|
||||||
signer_keys,
|
|
||||||
command.mode,
|
command.mode,
|
||||||
command.compression,
|
command.compression,
|
||||||
Some(sq.time),
|
Some(sq.time),
|
||||||
@ -91,8 +85,7 @@ pub fn encrypt<'a, 'b: 'a>(
|
|||||||
npasswords: usize,
|
npasswords: usize,
|
||||||
password_files: &[PathBuf],
|
password_files: &[PathBuf],
|
||||||
recipients: &'b [openpgp::Cert],
|
recipients: &'b [openpgp::Cert],
|
||||||
signers: Vec<openpgp::Cert>,
|
mut signers: Vec<Box<dyn crypto::Signer + Send + Sync>>,
|
||||||
signer_keys: &[KeyHandle],
|
|
||||||
mode: EncryptPurpose,
|
mode: EncryptPurpose,
|
||||||
compression: CompressionMode,
|
compression: CompressionMode,
|
||||||
time: Option<SystemTime>,
|
time: Option<SystemTime>,
|
||||||
@ -132,88 +125,6 @@ pub fn encrypt<'a, 'b: 'a>(
|
|||||||
|
|
||||||
let mode = KeyFlags::from(mode);
|
let mode = KeyFlags::from(mode);
|
||||||
|
|
||||||
let mut signers = sq.get_signing_keys(&signers, None)?;
|
|
||||||
|
|
||||||
let mut signer_keys = if signer_keys.is_empty() {
|
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
let mut ks = sq.key_store_or_else()?.lock().unwrap();
|
|
||||||
|
|
||||||
signer_keys.into_iter()
|
|
||||||
.map(|kh| {
|
|
||||||
let keys = ks.find_key(kh.clone())?;
|
|
||||||
|
|
||||||
match keys.len() {
|
|
||||||
0 => return Err(anyhow::anyhow!(
|
|
||||||
"{} is not present on keystore", kh)),
|
|
||||||
1 => (),
|
|
||||||
n => {
|
|
||||||
wprintln!("Warning: {} is present on multiple \
|
|
||||||
({}) devices",
|
|
||||||
kh, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut key = keys.into_iter().next().expect("checked for one");
|
|
||||||
|
|
||||||
match key.locked() {
|
|
||||||
Ok(Protection::Password(msg)) => {
|
|
||||||
let fpr = key.fingerprint();
|
|
||||||
let cert = sq.lookup_one(
|
|
||||||
&KeyHandle::from(&fpr), None, true);
|
|
||||||
let display = match cert {
|
|
||||||
Ok(cert) => {
|
|
||||||
format!(" ({})", sq.best_userid(&cert, true))
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
"".to_string()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let keyid = KeyID::from(&fpr);
|
|
||||||
|
|
||||||
if let Some(msg) = msg {
|
|
||||||
wprintln!("{}", msg);
|
|
||||||
}
|
|
||||||
loop {
|
|
||||||
let password = Password::from(rpassword::prompt_password(
|
|
||||||
format!("Enter password to unlock {}{}: ",
|
|
||||||
keyid, display))?);
|
|
||||||
match key.unlock(password) {
|
|
||||||
Ok(()) => break,
|
|
||||||
Err(err) => {
|
|
||||||
wprintln!("Unlocking {}: {}.", keyid, err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(Protection::Unlocked) => {
|
|
||||||
// Already unlocked, nothing to do.
|
|
||||||
}
|
|
||||||
Ok(Protection::UnknownProtection(msg))
|
|
||||||
| Ok(Protection::ExternalPassword(msg))
|
|
||||||
| Ok(Protection::ExternalTouch(msg))
|
|
||||||
| Ok(Protection::ExternalOther(msg)) =>
|
|
||||||
{
|
|
||||||
// Locked.
|
|
||||||
wprintln!("Key is locked{}",
|
|
||||||
if let Some(msg) = msg {
|
|
||||||
format!(": {}", msg)
|
|
||||||
} else {
|
|
||||||
"".into()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
// Failed to get the key's locked status. Just print
|
|
||||||
// a warning now. We'll (probably) fail more later.
|
|
||||||
wprintln!("Getting {}'s status: {}",
|
|
||||||
key.keyid(), err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(key)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>>>()?
|
|
||||||
};
|
|
||||||
|
|
||||||
// Build a vector of recipients to hand to Encryptor.
|
// Build a vector of recipients to hand to Encryptor.
|
||||||
let mut recipient_subkeys: Vec<Recipient> = Vec::new();
|
let mut recipient_subkeys: Vec<Recipient> = Vec::new();
|
||||||
for cert in recipients.iter() {
|
for cert in recipients.iter() {
|
||||||
@ -277,21 +188,15 @@ pub fn encrypt<'a, 'b: 'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Optionally sign message.
|
// Optionally sign message.
|
||||||
if ! signers.is_empty() || ! signer_keys.is_empty() {
|
if let Some(first) = signers.pop() {
|
||||||
let mut signer = if ! signers.is_empty() {
|
let mut signer = Signer::new(sink, first);
|
||||||
Signer::new(sink, signers.pop().unwrap())
|
|
||||||
} else {
|
|
||||||
Signer::new(sink, signer_keys.pop().unwrap())
|
|
||||||
};
|
|
||||||
if let Some(time) = time {
|
if let Some(time) = time {
|
||||||
signer = signer.creation_time(time);
|
signer = signer.creation_time(time);
|
||||||
}
|
}
|
||||||
for s in signers {
|
for s in signers {
|
||||||
signer = signer.add_signer(s);
|
signer = signer.add_signer(s);
|
||||||
}
|
}
|
||||||
for s in signer_keys {
|
|
||||||
signer = signer.add_signer(s);
|
|
||||||
}
|
|
||||||
for r in recipients.iter() {
|
for r in recipients.iter() {
|
||||||
signer = signer.add_intended_recipient(r);
|
signer = signer.add_intended_recipient(r);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user