Add support for using a key store.

- Support using keys managed by `sequoia-keystore`.

  - When decrypting a message, have `sq` automatically ask the
    key store to decrypt the PKESKs.

  - Extend `sq sign` and `sq encrypt` with the `--signer-key`
    parameter to use a key managed by the keystore.

  - Add two top-level options: `--no-key-store`, which disables the
    use of the key store, and `--key-store`, which uses an alternate
    key store instance.

  - Add `sq key list` to list keys on the key store.
This commit is contained in:
Neal H. Walfield 2024-01-18 18:09:59 +01:00 committed by Neal H. Walfield
parent c8567714e5
commit 27093c1709
No known key found for this signature in database
GPG Key ID: 6863C9AD5B4D22D3
30 changed files with 1087 additions and 311 deletions

184
Cargo.lock generated
View File

@ -288,6 +288,17 @@ version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "blanket"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0b121a9fe0df916e362fb3271088d071159cdf11db0e4182d02152850756eff"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.48",
]
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@ -403,6 +414,45 @@ dependencies = [
"cipher", "cipher",
] ]
[[package]]
name = "capnp"
version = "0.18.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b671a5b39eadb909b0c2b81d22a400d446526e651e64be9eb6674b33644a4"
dependencies = [
"embedded-io",
]
[[package]]
name = "capnp-futures"
version = "0.18.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8697b857f5b014ff378f02817426d3b6fb90a69f32e330fe010f24fe10cf8f1"
dependencies = [
"capnp",
"futures",
]
[[package]]
name = "capnp-rpc"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b87a9e0f74600628e227d39b79ef8652c558a408999ac46ba22b19dbad0010"
dependencies = [
"capnp",
"capnp-futures",
"futures",
]
[[package]]
name = "capnpc"
version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a642faaaa78187e70bdcc0014c593c213553cfeda3b15054426d0d596048b131"
dependencies = [
"capnp",
]
[[package]] [[package]]
name = "cast5" name = "cast5"
version = "0.11.1" version = "0.11.1"
@ -696,6 +746,16 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "ctor"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e"
dependencies = [
"quote",
"syn 2.0.48",
]
[[package]] [[package]]
name = "ctr" name = "ctr"
version = "0.9.2" version = "0.9.2"
@ -991,6 +1051,12 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "embedded-io"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658bbadc628dc286b9ae02f0cb0f5411c056eb7487b72f0083203f115de94060"
[[package]] [[package]]
name = "ena" name = "ena"
version = "0.14.2" version = "0.14.2"
@ -1234,6 +1300,21 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "futures"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.30" version = "0.3.30"
@ -1241,6 +1322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink",
] ]
[[package]] [[package]]
@ -1249,6 +1331,17 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-executor"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.30" version = "0.3.30"
@ -1284,9 +1377,13 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [ dependencies = [
"futures-channel",
"futures-core", "futures-core",
"futures-io",
"futures-macro", "futures-macro",
"futures-sink",
"futures-task", "futures-task",
"memchr",
"pin-project-lite", "pin-project-lite",
"pin-utils", "pin-utils",
"slab", "slab",
@ -2356,6 +2453,12 @@ dependencies = [
"windows-targets 0.48.5", "windows-targets 0.48.5",
] ]
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]] [[package]]
name = "peeking_take_while" name = "peeking_take_while"
version = "0.1.2" version = "0.1.2"
@ -3043,6 +3146,84 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "sequoia-ipc"
version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94fd8161ea44e9802c622e4cf088a6e9854baa573d1638f40600f76af90a9194"
dependencies = [
"anyhow",
"buffered-reader",
"capnp-rpc",
"crossbeam-utils",
"ctor",
"dirs",
"fs2",
"futures",
"lalrpop",
"lalrpop-util",
"lazy_static",
"libc",
"memsec",
"rand",
"sequoia-openpgp",
"socket2",
"tempfile",
"thiserror",
"tokio",
"tokio-util",
"winapi",
]
[[package]]
name = "sequoia-keystore"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df8e6116f15b027cc5cc23093985cad774fa72671bf643813f9ef331765e9da6"
dependencies = [
"anyhow",
"capnp",
"capnpc",
"dirs",
"env_logger",
"lazy_static",
"log",
"paste",
"sequoia-ipc",
"sequoia-keystore-backend",
"sequoia-keystore-softkeys",
"sequoia-openpgp",
"thiserror",
"tokio",
"tokio-util",
]
[[package]]
name = "sequoia-keystore-backend"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaef68a858310acd7557868cf35ad4a394e155a1d6e5de8e7c651cb07e6f96fb"
dependencies = [
"anyhow",
"blanket",
"sequoia-openpgp",
"thiserror",
]
[[package]]
name = "sequoia-keystore-softkeys"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d24b52535e007fdefb5559902cf186fa5c2e4709d65e2ab8a99bf2fc320eccaa"
dependencies = [
"anyhow",
"dirs",
"lazy_static",
"log",
"sequoia-keystore-backend",
"sequoia-openpgp",
]
[[package]] [[package]]
name = "sequoia-net" name = "sequoia-net"
version = "0.28.0" version = "0.28.0"
@ -3163,12 +3344,14 @@ dependencies = [
"indicatif", "indicatif",
"itertools", "itertools",
"libc", "libc",
"once_cell",
"predicates", "predicates",
"regex", "regex",
"roff", "roff",
"rpassword", "rpassword",
"sequoia-autocrypt", "sequoia-autocrypt",
"sequoia-cert-store", "sequoia-cert-store",
"sequoia-keystore",
"sequoia-net", "sequoia-net",
"sequoia-openpgp", "sequoia-openpgp",
"sequoia-policy-config", "sequoia-policy-config",
@ -3791,6 +3974,7 @@ checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
"futures-io",
"futures-sink", "futures-sink",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",

View File

@ -42,7 +42,9 @@ clap = { version = "4", features = ["derive", "env", "string", "wrap_help"] }
humantime = "2" humantime = "2"
indicatif = "0.17" indicatif = "0.17"
itertools = ">=0.10, <0.13" itertools = ">=0.10, <0.13"
once_cell = "1.17"
sequoia-cert-store = "0.4.2" sequoia-cert-store = "0.4.2"
sequoia-keystore = { version = "0.1" }
sequoia-wot = "0.9" sequoia-wot = "0.9"
tempfile = "3.1" tempfile = "3.1"
tokio = { version = "1.13.1" } tokio = { version = "1.13.1" }

12
NEWS
View File

@ -27,6 +27,18 @@
write the assets to a predictable location, set the environment write the assets to a predictable location, set the environment
variable `ASSET_OUT_DIR` to a suitable location. variable `ASSET_OUT_DIR` to a suitable location.
- `sq` now uses `sequoia-keystore` for secret key operations.
When decrypting a message, `sq` will automatically ask the
keystore to decrypt the message. `sq sign --signer-key` can be
used to specify a signing key managed by the key store.
- New top-level option: `sq --no-key-store`: A new switch to
disable the use of the key store.
- New top-level option: `sq --key-store`: A new option to use an
alternate key store.
* Changes in 0.32.0 * Changes in 0.32.0
** New functionality ** New functionality
- Support for password-encrypted keys has been improved. For - Support for password-encrypted keys has been improved. For

File diff suppressed because it is too large Load Diff

View File

@ -137,6 +137,12 @@ pub struct Command {
help = "Signs the message using the key in KEY_FILE", help = "Signs the message using the key in KEY_FILE",
)] )]
pub signer_key_file: Vec<PathBuf>, pub signer_key_file: Vec<PathBuf>,
#[clap(
long = "signer-key",
value_name = "KEYID|FINGERPRINT",
help = "Signs the message using the specified key on the key store",
)]
pub signer_key: Vec<KeyHandle>,
#[clap( #[clap(
long = "private-key-store", long = "private-key-store",
value_name = "KEY_STORE", value_name = "KEY_STORE",

View File

@ -167,6 +167,7 @@ macro_rules! test_examples {
Command::cargo_bin(command[0]).unwrap() Command::cargo_bin(command[0]).unwrap()
.current_dir(&tmp_dir) .current_dir(&tmp_dir)
.env("SQ_CERT_STORE", &cert_store) .env("SQ_CERT_STORE", &cert_store)
.arg("--no-key-store")
.args(&command[1..]) .args(&command[1..])
.assert() .assert()
.success(); .success();

View File

@ -18,6 +18,11 @@ use crate::cli::types::FileOrStdin;
use crate::cli::types::FileOrStdout; use crate::cli::types::FileOrStdout;
use crate::cli::types::Time; use crate::cli::types::Time;
use crate::cli::examples;
use examples::Action;
use examples::Actions;
use examples::Example;
pub mod expire; pub mod expire;
/// The revocation reason for a certificate or subkey /// The revocation reason for a certificate or subkey
@ -80,6 +85,7 @@ pub struct Command {
#[derive(Debug, Subcommand)] #[derive(Debug, Subcommand)]
pub enum Subcommands { pub enum Subcommands {
List(ListCommand),
Generate(GenerateCommand), Generate(GenerateCommand),
Password(PasswordCommand), Password(PasswordCommand),
Expire(expire::Command), Expire(expire::Command),
@ -93,6 +99,27 @@ pub enum Subcommands {
Adopt(AdoptCommand), Adopt(AdoptCommand),
} }
const LIST_EXAMPLES: Actions = Actions {
actions: &[
Action::Example(Example {
comment: "\
Lists the keys managed by the keystore server.",
command: &[
"sq", "key", "list",
],
}),
]
};
test_examples!(sq_key_list, LIST_EXAMPLES);
#[derive(Debug, Args)]
#[clap(
about = "Lists keys managed by the key store",
after_help = LIST_EXAMPLES,
)]
pub struct ListCommand {
}
#[derive(Debug, Args)] #[derive(Debug, Args)]
#[clap( #[clap(
about = "Generates a new key", about = "Generates a new key",

View File

@ -146,7 +146,9 @@ pub fn build() -> Command {
Functionality is grouped and available using subcommands. This Functionality is grouped and available using subcommands. This
interface is not completely stateless. In particular, the user's interface is not completely stateless. In particular, the user's
default certificate store is used. This can be disabled using default certificate store is used. This can be disabled using
`--no-cert-store`. `--no-cert-store`. Similarly, a key store is used to manage and
protect secret key material. This can be disabled using
`--no-key-store`.
OpenPGP data can be provided in binary or ASCII armored form. This OpenPGP data can be provided in binary or ASCII armored form. This
will be handled automatically. Emitted OpenPGP data is ASCII armored will be handled automatically. Emitted OpenPGP data is ASCII armored
@ -172,6 +174,33 @@ pub struct SqCommand {
help = "Overwrites existing files" help = "Overwrites existing files"
)] )]
pub force: bool, pub force: bool,
#[clap(
long,
help = "Disables the use of the key store.",
long_help = "\
Disables the use of the key store.
It is still possible to use functionality that does not require the
key store."
)]
pub no_key_store: bool,
#[clap(
long,
value_name = "PATH",
env = "SQ_KEY_STORE",
conflicts_with_all = &[ "no_key_store" ],
help = "Overrides the key store server and its data",
long_help = "\
A key store server manages and protects secret key material. By
default, `sq` connects to the key store server listening on
`$XDG_DATA_HOME/sequoia`. If no key store server is running, one is
started.
This option causes `sq` to use an alternate key store server. If
necessary, a key store server is started, and configured to look for
its data in the specified location."
)]
pub key_store: Option<PathBuf>,
#[clap( #[clap(
long, long,
global = true, global = true,

View File

@ -4,6 +4,9 @@ use std::path::PathBuf;
use clap::Parser; use clap::Parser;
use sequoia_openpgp as openpgp;
use openpgp::KeyHandle;
use super::types::ClapData; use super::types::ClapData;
use super::types::FileOrStdin; use super::types::FileOrStdin;
use super::types::FileOrStdout; use super::types::FileOrStdout;
@ -118,6 +121,12 @@ pub struct Command {
help = "Signs the message using the key in KEY_FILE", help = "Signs the message using the key in KEY_FILE",
)] )]
pub secret_key_file: Vec<PathBuf>, pub secret_key_file: Vec<PathBuf>,
#[clap(
long = "signer-key",
value_name = "KEYID|FINGERPRINT",
help = "Signs the message using the specified key on the key store",
)]
pub signer_key: Vec<KeyHandle>,
#[clap( #[clap(
long, long,
value_names = &["NAME", "VALUE"], value_names = &["NAME", "VALUE"],

View File

@ -19,6 +19,8 @@ use openpgp::parse::stream::{
VerificationHelper, DecryptionHelper, DecryptorBuilder, MessageStructure, VerificationHelper, DecryptionHelper, DecryptorBuilder, MessageStructure,
}; };
use sequoia_keystore as keystore;
use crate::{ use crate::{
cli, cli,
commands::{ commands::{
@ -200,6 +202,24 @@ impl<'a, 'certdb> Helper<'a, 'certdb> {
} }
} }
/// Checks if a session key can decrypt the packet parser using
/// `decrypt`.
fn try_session_key<D>(&self, keyid: &KeyID,
algo: SymmetricAlgorithm, sk: SessionKey,
decrypt: &mut D)
-> Option<Option<Fingerprint>>
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool
{
if decrypt(algo, &sk) {
if self.dump_session_key {
wprintln!("Session key: {}", hex::encode(&sk));
}
Some(self.key_identities.get(keyid).cloned())
} else {
None
}
}
/// Tries to decrypt the given PKESK packet with `keypair` and try /// Tries to decrypt the given PKESK packet with `keypair` and try
/// to decrypt the packet parser using `decrypt`. /// to decrypt the packet parser using `decrypt`.
fn try_decrypt<D>(&self, pkesk: &PKESK, fn try_decrypt<D>(&self, pkesk: &PKESK,
@ -210,19 +230,8 @@ impl<'a, 'certdb> Helper<'a, 'certdb> {
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool
{ {
let keyid = keypair.public().fingerprint().into(); let keyid = keypair.public().fingerprint().into();
match pkesk.decrypt(&mut *keypair, sym_algo) let (sym_algo, sk) = pkesk.decrypt(&mut *keypair, sym_algo)?;
.and_then(|(algo, sk)| { self.try_session_key(&keyid, sym_algo, sk, decrypt)
if decrypt(algo, &sk) { Some(sk) } else { None }
})
{
Some(sk) => {
if self.dump_session_key {
wprintln!("Session key: {}", hex::encode(&sk));
}
Some(self.key_identities.get(&keyid).cloned())
},
None => None,
}
} }
} }
@ -261,6 +270,9 @@ impl<'a, 'certdb> DecryptionHelper for Helper<'a, 'certdb> {
} }
} }
// Now, we try the secret keys that the user supplied on the
// command line.
// First, we try those keys that we can use without prompting // First, we try those keys that we can use without prompting
// for a password. // for a password.
for pkesk in pkesks { for pkesk in pkesks {
@ -365,6 +377,63 @@ impl<'a, 'certdb> DecryptionHelper for Helper<'a, 'certdb> {
} }
} }
// Try the key store.
match self.vhelper.config.key_store_or_else() {
Ok(ks) => {
let mut ks = ks.lock().unwrap();
match ks.decrypt(&pkesks[..]) {
// Success!
Ok((_i, fpr, sym_algo, sk)) => {
if let Some(fp) =
self.try_session_key(
&KeyID::from(fpr), sym_algo, sk, &mut decrypt)
{
return Ok(fp);
}
}
Err(err) => {
match err.downcast() {
Ok(keystore::Error::InaccessibleDecryptionKey(keys)) => {
for key_status in keys.into_iter() {
let pkesk = key_status.pkesk().clone();
let mut key = key_status.into_key();
let keyid = key.keyid();
let keypair = loop {
let password = rpassword::prompt_password(
format!(
"Enter password to unlock {}: ",
keyid))?
.into();
if let Ok(()) = key.unlock(password) {
break Box::new(key);
} else {
wprintln!("Bad password.");
}
};
if let Some(fp) = self.try_decrypt(
&pkesk, sym_algo, keypair, &mut decrypt)
{
return Ok(fp);
}
}
}
// Failed to decrypt using the keystore.
Ok(_err) => (),
Err(_err) => (),
}
}
}
}
Err(err) => {
wprintln!("Warning: unable to connect to keystore: {}",
err);
}
}
if skesks.is_empty() { if skesks.is_empty() {
return return
Err(anyhow::anyhow!("No key to decrypt message")); Err(anyhow::anyhow!("No key to decrypt message"));

View File

@ -9,6 +9,9 @@ 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;
@ -21,6 +24,7 @@ use openpgp::serialize::stream::padding::Padder;
use openpgp::types::CompressionAlgorithm; use openpgp::types::CompressionAlgorithm;
use openpgp::types::KeyFlags; use openpgp::types::KeyFlags;
use crate::best_effort_primary_uid;
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;
@ -61,8 +65,10 @@ pub fn dispatch(config: Config, command: cli::encrypt::Command) -> Result<()> {
let additional_secrets = let additional_secrets =
load_certs(command.signer_key_file.iter().map(|s| s.as_ref()))?; load_certs(command.signer_key_file.iter().map(|s| s.as_ref()))?;
let signer_keys = &command.signer_key[..];
encrypt( encrypt(
&config,
&config.policy, &config.policy,
command.private_key_store.as_deref(), command.private_key_store.as_deref(),
command.input, command.input,
@ -70,6 +76,7 @@ pub fn dispatch(config: Config, command: cli::encrypt::Command) -> Result<()> {
command.symmetric as usize, command.symmetric as usize,
&recipients, &recipients,
additional_secrets, additional_secrets,
signer_keys,
command.mode, command.mode,
command.compression, command.compression,
Some(config.time), Some(config.time),
@ -82,6 +89,7 @@ pub fn dispatch(config: Config, command: cli::encrypt::Command) -> Result<()> {
} }
pub fn encrypt<'a, 'b: 'a>( pub fn encrypt<'a, 'b: 'a>(
config: &Config,
policy: &'b dyn Policy, policy: &'b dyn Policy,
private_key_store: Option<&str>, private_key_store: Option<&str>,
input: FileOrStdin, input: FileOrStdin,
@ -89,6 +97,7 @@ pub fn encrypt<'a, 'b: 'a>(
npasswords: usize, npasswords: usize,
recipients: &'b [openpgp::Cert], recipients: &'b [openpgp::Cert],
signers: Vec<openpgp::Cert>, signers: Vec<openpgp::Cert>,
signer_keys: &[KeyHandle],
mode: EncryptPurpose, mode: EncryptPurpose,
compression: CompressionMode, compression: CompressionMode,
time: Option<SystemTime>, time: Option<SystemTime>,
@ -125,6 +134,75 @@ pub fn encrypt<'a, 'b: 'a>(
let mut signers = get_signing_keys( let mut signers = get_signing_keys(
&signers, policy, private_key_store, time, None)?; &signers, policy, private_key_store, time, None)?;
let mut signer_keys = if signer_keys.is_empty() {
Vec::new()
} else {
let mut ks = config.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 => {
eprintln!("Warning: {} is present on multiple \
({}) devices",
kh, n);
}
}
let mut key = keys.into_iter().next().expect("checked for one");
match key.locked() {
Ok(true) => {
let fpr = key.fingerprint();
let cert = config.lookup_one(
&KeyHandle::from(&fpr), None, true);
let display = match cert {
Ok(cert) => {
format!(" ({})",
String::from_utf8_lossy(
best_effort_primary_uid(
&cert, &config.policy,
config.time)
.value()))
}
Err(_) => {
"".to_string()
}
};
let keyid = KeyID::from(&fpr);
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(false) => {
// Already unlocked, nothing to do.
}
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() {
@ -188,13 +266,20 @@ pub fn encrypt<'a, 'b: 'a>(
} }
// Optionally sign message. // Optionally sign message.
if ! signers.is_empty() { if ! signers.is_empty() || ! signer_keys.is_empty() {
let mut signer = Signer::new(sink, signers.pop().unwrap().0); let mut signer = if ! signers.is_empty() {
for s in signers { Signer::new(sink, signers.pop().unwrap().0)
signer = signer.add_signer(s.0); } 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 {
signer = signer.add_signer(s.0);
}
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);

View File

@ -11,6 +11,8 @@ use attest_certifications::attest_certifications;
mod expire; mod expire;
mod extract_cert; mod extract_cert;
use extract_cert::extract_cert; use extract_cert::extract_cert;
mod list;
use list::list;
mod generate; mod generate;
use generate::generate; use generate::generate;
mod password; mod password;
@ -24,6 +26,7 @@ pub fn dispatch(config: Config, command: cli::key::Command) -> Result<()>
{ {
use cli::key::Subcommands::*; use cli::key::Subcommands::*;
match command.subcommand { match command.subcommand {
List(c) => list(config, c)?,
Generate(c) => generate(config, c)?, Generate(c) => generate(config, c)?,
Password(c) => password(config, c)?, Password(c) => password(config, c)?,
Expire(c) => expire::dispatch(config, c)?, Expire(c) => expire::dispatch(config, c)?,

79
src/commands/key/list.rs Normal file
View File

@ -0,0 +1,79 @@
use sequoia_openpgp as openpgp;
use openpgp::KeyHandle;
use crate::best_effort_primary_uid;
use crate::cli;
use crate::Config;
use crate::Result;
pub fn list(config: Config, _command: cli::key::ListCommand) -> Result<()> {
// Start and connect to the keystore.
let ks = if let Some(ks) = config.key_store()? {
ks
} else {
// The key store is disabled. Don't fail, just return
// nothing.
return Ok(());
};
let mut ks = ks.lock().unwrap();
let mut backends = ks.backends()?;
for backend in &mut backends {
let devices = backend.list()?;
if devices.len() == 0 {
println!(" - Backend {} has no devices.", backend.id()?);
} else {
println!(" - {}", backend.id()?);
}
for mut device in devices {
let keys = device.list()?;
if keys.len() == 0 {
println!(" - Device {} has no keys.", device.id()?);
} else {
println!(" - {}", device.id()?);
}
for mut key in keys.into_iter() {
let fpr = KeyHandle::from(key.fingerprint());
let userid = if let Ok(cert) = config.lookup_one(&fpr, None, true) {
best_effort_primary_uid(&cert, &config.policy, None).to_string()
} else {
"(Unknown)".to_string()
};
let signing_capable = key.signing_capable().unwrap_or(false);
let decryption_capable = key.decryption_capable().unwrap_or(false);
println!(" - {} {} ({}, {}, {})",
fpr, userid,
if key.available().unwrap_or(false) {
"available"
} else {
"not available"
},
if key.locked().unwrap_or(false) {
"locked"
} else {
"not locked"
},
match (signing_capable, decryption_capable) {
(true, true) => {
"for signing and decryption"
}
(true, false) => {
"for signing"
}
(false, true) => {
"for decryption"
}
(false, false) => {
"unusable"
}
});
}
}
}
Ok(())
}

View File

@ -7,6 +7,9 @@ use tempfile::NamedTempFile;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp::armor; use openpgp::armor;
use openpgp::crypto::Password;
use openpgp::KeyHandle;
use openpgp::KeyID;
use openpgp::{Packet, Result}; use openpgp::{Packet, Result};
use openpgp::packet::prelude::*; use openpgp::packet::prelude::*;
use openpgp::packet::signature::subpacket::NotationData; use openpgp::packet::signature::subpacket::NotationData;
@ -20,6 +23,7 @@ use openpgp::serialize::stream::{
}; };
use openpgp::types::SignatureType; use openpgp::types::SignatureType;
use crate::best_effort_primary_uid;
use crate::Config; use crate::Config;
use crate::load_certs; use crate::load_certs;
use crate::parse_notations; use crate::parse_notations;
@ -47,6 +51,7 @@ pub fn dispatch(config: Config, command: cli::sign::Command) -> Result<()> {
let private_key_store = command.private_key_store.as_deref(); let private_key_store = command.private_key_store.as_deref();
let secrets = let secrets =
load_certs(command.secret_key_file.iter().map(|s| s.as_ref()))?; load_certs(command.secret_key_file.iter().map(|s| s.as_ref()))?;
let signer_keys = &command.signer_key[..];
let time = Some(config.time); let time = Some(config.time);
let notations = parse_notations(command.notation)?; let notations = parse_notations(command.notation)?;
@ -70,6 +75,7 @@ pub fn dispatch(config: Config, command: cli::sign::Command) -> Result<()> {
&mut input, &mut input,
output, output,
secrets, secrets,
signer_keys,
detached, detached,
binary, binary,
append, append,
@ -87,6 +93,7 @@ pub fn sign<'a, 'certdb>(
input: &'a mut (dyn io::Read + Sync + Send), input: &'a mut (dyn io::Read + Sync + Send),
output: &'a FileOrStdout, output: &'a FileOrStdout,
secrets: Vec<openpgp::Cert>, secrets: Vec<openpgp::Cert>,
signer_keys: &[KeyHandle],
detached: bool, detached: bool,
binary: bool, binary: bool,
append: bool, append: bool,
@ -102,6 +109,7 @@ pub fn sign<'a, 'certdb>(
input, input,
output, output,
secrets, secrets,
signer_keys,
detached, detached,
binary, binary,
append, append,
@ -126,6 +134,7 @@ fn sign_data<'a, 'certdb>(
input: &'a mut (dyn io::Read + Sync + Send), input: &'a mut (dyn io::Read + Sync + Send),
output_path: &'a FileOrStdout, output_path: &'a FileOrStdout,
secrets: Vec<openpgp::Cert>, secrets: Vec<openpgp::Cert>,
signer_keys: &[KeyHandle],
detached: bool, detached: bool,
binary: bool, binary: bool,
append: bool, append: bool,
@ -169,7 +178,77 @@ fn sign_data<'a, 'certdb>(
let mut keypairs = super::get_signing_keys( let mut keypairs = super::get_signing_keys(
&secrets, &config.policy, private_key_store, time, None)?; &secrets, &config.policy, private_key_store, time, None)?;
if keypairs.is_empty() {
let mut signer_keys = if signer_keys.is_empty() {
Vec::new()
} else {
let mut ks = config.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 => {
eprintln!("Warning: {} is present on multiple \
({}) devices",
kh, n);
}
}
let mut key = keys.into_iter().next().expect("checked for one");
match key.locked() {
Ok(true) => {
let fpr = key.fingerprint();
let cert = config.lookup_one(
&KeyHandle::from(&fpr), None, true);
let display = match cert {
Ok(cert) => {
format!(" ({})",
String::from_utf8_lossy(
best_effort_primary_uid(
&cert, &config.policy,
config.time)
.value()))
}
Err(_) => {
"".to_string()
}
};
let keyid = KeyID::from(&fpr);
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(false) => {
// Already unlocked, nothing to do.
}
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<_>>>()?
};
if keypairs.is_empty() && signer_keys.is_empty() {
return Err(anyhow::anyhow!("No signing keys found")); return Err(anyhow::anyhow!("No signing keys found"));
} }
@ -202,14 +281,26 @@ fn sign_data<'a, 'certdb>(
*critical)?; *critical)?;
} }
let mut signer = Signer::with_template( let mut signer = if keypairs.is_empty() {
message, keypairs.pop().unwrap().0, builder); Signer::with_template(
message,
signer_keys.pop().unwrap(),
builder)
} else {
Signer::with_template(
message,
keypairs.pop().unwrap().0,
builder)
};
if let Some(time) = time { if let Some(time) = time {
signer = signer.creation_time(time); signer = signer.creation_time(time);
} }
for s in keypairs { for s in keypairs {
signer = signer.add_signer(s.0); signer = signer.add_signer(s.0);
} }
for k in signer_keys {
signer = signer.add_signer(k);
}
if detached { if detached {
signer = signer.detached(); signer = signer.detached();
} }

View File

@ -9,15 +9,17 @@
use anyhow::Context as _; use anyhow::Context as _;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::cell::OnceCell;
use std::collections::btree_map::{BTreeMap, Entry}; use std::collections::btree_map::{BTreeMap, Entry};
use std::fmt; use std::fmt;
use std::io; use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use std::sync::Mutex;
use std::time::SystemTime; use std::time::SystemTime;
use std::sync::Arc; use std::sync::Arc;
use once_cell::sync::OnceCell;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp::{ use openpgp::{
@ -48,6 +50,8 @@ use cert_store::store::UserIDQueryParams;
use sequoia_wot as wot; use sequoia_wot as wot;
use wot::store::Store as _; use wot::store::Store as _;
use sequoia_keystore as keystore;
use clap::FromArgMatches; use clap::FromArgMatches;
#[macro_use] mod macros; #[macro_use] mod macros;
@ -332,6 +336,11 @@ pub struct Config<'a> {
trust_roots: Vec<Fingerprint>, trust_roots: Vec<Fingerprint>,
// The local trust root, as set in the cert store. // The local trust root, as set in the cert store.
trust_root_local: OnceCell<Option<Fingerprint>>, trust_root_local: OnceCell<Option<Fingerprint>>,
// The key store.
no_key_store: bool,
key_store_path: Option<PathBuf>,
key_store: OnceCell<Mutex<keystore::Keystore>>,
} }
impl<'store> Config<'store> { impl<'store> Config<'store> {
@ -542,6 +551,50 @@ impl<'store> Config<'store> {
.ok_or_else(|| anyhow::anyhow!(NO_CERTD_ERR)) .ok_or_else(|| anyhow::anyhow!(NO_CERTD_ERR))
} }
/// Returns the key store.
///
/// If the key store is disabled, returns `Ok(None)`. If it is not yet
/// open, opens it.
fn key_store(&self) -> Result<Option<&Mutex<keystore::Keystore>>> {
if self.no_key_store {
return Ok(None);
}
self.key_store
.get_or_try_init(|| {
let dir_;
let dir = if let Some(dir) = self.key_store_path.as_ref() {
dir
} else if let Some(dir) = dirs::data_dir() {
dir_ = dir.join("sequoia");
&dir_
} else {
return Err(anyhow::anyhow!(
"No key store, the XDG data directory is not defined"));
};
let c = keystore::Context::configure()
.home(dir)
.build()?;
let ks = keystore::Keystore::connect(&c)
.context("Connecting to key store")?;
Ok(Mutex::new(ks))
})
.map(Some)
}
/// Returns the key store.
///
/// If the key store is disabled, returns an error.
fn key_store_or_else(&self) -> Result<&Mutex<keystore::Keystore>> {
self.key_store().and_then(|key_store| key_store.ok_or_else(|| {
anyhow::anyhow!("Operation requires a key store, \
but the key store is disabled")
}))
}
/// Looks up an identifier. /// Looks up an identifier.
/// ///
/// This matches on both the primary key and the subkeys. /// This matches on both the primary key and the subkeys.
@ -1017,6 +1070,9 @@ fn main() -> Result<()> {
cert_store: OnceCell::new(), cert_store: OnceCell::new(),
trust_roots: c.trust_roots.clone(), trust_roots: c.trust_roots.clone(),
trust_root_local: Default::default(), trust_root_local: Default::default(),
no_key_store: c.no_key_store,
key_store_path: c.key_store.clone(),
key_store: OnceCell::new(),
}; };
commands::dispatch(config, c) commands::dispatch(config, c)

View File

@ -38,6 +38,7 @@ pub fn sq_key_generate(
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"generate", "generate",
"--time", "--time",

View File

@ -76,6 +76,7 @@ mod integration {
sq() sq()
.current_dir(&dir) .current_dir(&dir)
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("cert").arg("lint") .arg("cert").arg("lint")
.arg("--time").arg(FROZEN_TIME) .arg("--time").arg(FROZEN_TIME)
.arg(filename) .arg(filename)
@ -110,6 +111,7 @@ mod integration {
let mut cmd = cmd.current_dir(&dir) let mut cmd = cmd.current_dir(&dir)
.args(&[ .args(&[
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"cert", "lint", "cert", "lint",
"--time", FROZEN_TIME, "--time", FROZEN_TIME,
"--fix", &format!("{}-{}.pgp", base, suffix) "--fix", &format!("{}-{}.pgp", base, suffix)
@ -130,6 +132,7 @@ mod integration {
Command::cargo_bin("sq").unwrap() Command::cargo_bin("sq").unwrap()
.current_dir(&dir) .current_dir(&dir)
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("cert").arg("lint") .arg("cert").arg("lint")
.arg("--time").arg(FROZEN_TIME) .arg("--time").arg(FROZEN_TIME)
.arg("-") .arg("-")
@ -428,6 +431,7 @@ mod integration {
.current_dir(&dir()) .current_dir(&dir())
.args(&[ .args(&[
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"cert", "lint", "cert", "lint",
"--time", FROZEN_TIME, "--time", FROZEN_TIME,
"--list-keys", "--list-keys",
@ -448,6 +452,7 @@ mod integration {
.current_dir(&dir()) .current_dir(&dir())
.args(&[ .args(&[
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"cert", "lint", "cert", "lint",
"--time", FROZEN_TIME, "--time", FROZEN_TIME,
"msg.sig", "msg.sig",

View File

@ -42,6 +42,7 @@ fn sq_certify() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("pki").arg("certify") .arg("pki").arg("certify")
.arg(alice_pgp.to_str().unwrap()) .arg(alice_pgp.to_str().unwrap())
.arg(bob_pgp.to_str().unwrap()) .arg(bob_pgp.to_str().unwrap())
@ -81,6 +82,7 @@ fn sq_certify() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("pki").arg("certify") .arg("pki").arg("certify")
.arg(alice_pgp.to_str().unwrap()) .arg(alice_pgp.to_str().unwrap())
.arg(bob_pgp.to_str().unwrap()) .arg(bob_pgp.to_str().unwrap())
@ -120,6 +122,7 @@ fn sq_certify() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("pki").arg("certify") .arg("pki").arg("certify")
.arg(alice_pgp.to_str().unwrap()) .arg(alice_pgp.to_str().unwrap())
.arg(bob_pgp.to_str().unwrap()) .arg(bob_pgp.to_str().unwrap())
@ -167,6 +170,7 @@ fn sq_certify() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("pki").arg("certify") .arg("pki").arg("certify")
.arg(alice_pgp.to_str().unwrap()) .arg(alice_pgp.to_str().unwrap())
.arg(bob_pgp.to_str().unwrap()) .arg(bob_pgp.to_str().unwrap())
@ -178,6 +182,7 @@ fn sq_certify() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("pki").arg("certify") .arg("pki").arg("certify")
.args(["--notation", "foo", "bar"]) .args(["--notation", "foo", "bar"])
.args(["--notation", "!foo", "xyzzy"]) .args(["--notation", "!foo", "xyzzy"])
@ -303,6 +308,7 @@ fn sq_certify_creation_time() -> Result<()>
// Build up the command line. // Build up the command line.
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"pki", "certify", "pki", "certify",
&alice_pgp.to_string_lossy(), &alice_pgp.to_string_lossy(),
&bob_pgp.to_string_lossy(), bob, &bob_pgp.to_string_lossy(), bob,
@ -389,6 +395,7 @@ fn sq_certify_with_expired_key() -> Result<()>
// Make sure using an expired key fails by default. // Make sure using an expired key fails by default.
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"pki", "certify", "pki", "certify",
&alice_pgp.to_string_lossy(), &alice_pgp.to_string_lossy(),
&bob_pgp.to_string_lossy(), bob ]); &bob_pgp.to_string_lossy(), bob ]);
@ -398,6 +405,7 @@ fn sq_certify_with_expired_key() -> Result<()>
// Try again. // Try again.
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"pki", "certify", "pki", "certify",
"--allow-not-alive-certifier", "--allow-not-alive-certifier",
&alice_pgp.to_string_lossy(), &alice_pgp.to_string_lossy(),
@ -483,6 +491,7 @@ fn sq_certify_with_revoked_key() -> Result<()>
// Make sure using an expired key fails by default. // Make sure using an expired key fails by default.
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"pki", "certify", "pki", "certify",
&alice_pgp.to_string_lossy(), &alice_pgp.to_string_lossy(),
&bob_pgp.to_string_lossy(), bob ]); &bob_pgp.to_string_lossy(), bob ]);
@ -492,6 +501,7 @@ fn sq_certify_with_revoked_key() -> Result<()>
// Try again. // Try again.
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"pki", "certify", "pki", "certify",
"--allow-revoked-certifier", "--allow-revoked-certifier",
&alice_pgp.to_string_lossy(), &alice_pgp.to_string_lossy(),

View File

@ -20,6 +20,7 @@ mod integration {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"]) .args(["--session-key", "1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"])
.arg(artifact("messages/rsa.msg.pgp")) .arg(artifact("messages/rsa.msg.pgp"))
@ -34,6 +35,7 @@ mod integration {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "9:1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"]) .args(["--session-key", "9:1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"])
.arg(artifact("messages/rsa.msg.pgp")) .arg(artifact("messages/rsa.msg.pgp"))
@ -48,6 +50,7 @@ mod integration {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "2FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"]) .args(["--session-key", "2FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"])
.args(["--session-key", "9:1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"]) .args(["--session-key", "9:1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"])
@ -64,6 +67,7 @@ mod integration {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "BB9CCB8EDE22DC222C83BD1C63AEB97335DDC7B696DB171BD16EAA5784CC0478"]) .args(["--session-key", "BB9CCB8EDE22DC222C83BD1C63AEB97335DDC7B696DB171BD16EAA5784CC0478"])
.arg(artifact("messages/rsa.msg.pgp")) .arg(artifact("messages/rsa.msg.pgp"))

View File

@ -189,6 +189,7 @@ mod integration {
for key in decryption_keys.iter() { for key in decryption_keys.iter() {
let mut cmd = Command::cargo_bin("sq").unwrap(); let mut cmd = Command::cargo_bin("sq").unwrap();
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"decrypt", "decrypt",
"--recipient-file", "--recipient-file",
&key]) &key])
@ -375,6 +376,7 @@ mod integration {
for key in decryption_keys.iter() { for key in decryption_keys.iter() {
let mut cmd = Command::cargo_bin("sq").unwrap(); let mut cmd = Command::cargo_bin("sq").unwrap();
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"decrypt", "decrypt",
"--recipient-file", "--recipient-file",
&key]) &key])

View File

@ -141,7 +141,10 @@ mod integration {
#[test] #[test]
fn adopt_encryption() -> Result<()> { fn adopt_encryption() -> Result<()> {
// Adopt an encryption subkey. // Adopt an encryption subkey.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--key").arg(alice_encryption().0.to_hex()) .arg("--key").arg(alice_encryption().0.to_hex())
@ -157,7 +160,10 @@ mod integration {
#[test] #[test]
fn adopt_signing() -> Result<()> { fn adopt_signing() -> Result<()> {
// Adopt a signing subkey (subkey has secret key material). // Adopt a signing subkey (subkey has secret key material).
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--key").arg(alice_signing().0.to_hex()) .arg("--key").arg(alice_signing().0.to_hex())
@ -173,7 +179,10 @@ mod integration {
#[test] #[test]
fn adopt_certification() -> Result<()> { fn adopt_certification() -> Result<()> {
// Adopt a certification subkey (subkey has secret key material). // Adopt a certification subkey (subkey has secret key material).
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(carol()) .arg(carol())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--key").arg(alice_primary().0.to_hex()) .arg("--key").arg(alice_primary().0.to_hex())
@ -189,7 +198,10 @@ mod integration {
#[test] #[test]
fn adopt_encryption_and_signing() -> Result<()> { fn adopt_encryption_and_signing() -> Result<()> {
// Adopt an encryption subkey and a signing subkey. // Adopt an encryption subkey and a signing subkey.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--key").arg(alice_signing().0.to_hex()) .arg("--key").arg(alice_signing().0.to_hex())
@ -209,7 +221,10 @@ mod integration {
#[test] #[test]
fn adopt_twice() -> Result<()> { fn adopt_twice() -> Result<()> {
// Adopt the same an encryption subkey twice. // Adopt the same an encryption subkey twice.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--key").arg(alice_encryption().0.to_hex()) .arg("--key").arg(alice_encryption().0.to_hex())
@ -226,7 +241,10 @@ mod integration {
#[test] #[test]
fn adopt_key_appears_twice() -> Result<()> { fn adopt_key_appears_twice() -> Result<()> {
// Adopt the an encryption subkey that appears twice. // Adopt the an encryption subkey that appears twice.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
@ -243,7 +261,10 @@ mod integration {
#[test] #[test]
fn adopt_own_encryption() -> Result<()> { fn adopt_own_encryption() -> Result<()> {
// Adopt its own encryption subkey. This should be a noop. // Adopt its own encryption subkey. This should be a noop.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(alice()) .arg(alice())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--key").arg(alice_encryption().0.to_hex()) .arg("--key").arg(alice_encryption().0.to_hex())
@ -259,7 +280,10 @@ mod integration {
#[test] #[test]
fn adopt_own_primary() -> Result<()> { fn adopt_own_primary() -> Result<()> {
// Adopt own primary key. // Adopt own primary key.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(bob()) .arg("--keyring").arg(bob())
.arg("--key").arg(bob_primary().0.to_hex()) .arg("--key").arg(bob_primary().0.to_hex())
@ -275,7 +299,10 @@ mod integration {
#[test] #[test]
fn adopt_missing() -> Result<()> { fn adopt_missing() -> Result<()> {
// Adopt a key that is not present. // Adopt a key that is not present.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(bob()) .arg("--keyring").arg(bob())
.arg("--key").arg("1234 5678 90AB CDEF 1234 5678 90AB CDEF") .arg("--key").arg("1234 5678 90AB CDEF 1234 5678 90AB CDEF")
@ -288,7 +315,10 @@ mod integration {
#[test] #[test]
fn adopt_from_multiple() -> Result<()> { fn adopt_from_multiple() -> Result<()> {
// Adopt from multiple certificates simultaneously. // Adopt from multiple certificates simultaneously.
Command::cargo_bin("sq").unwrap().arg("--no-cert-store").arg("key").arg("adopt") Command::cargo_bin("sq").unwrap()
.arg("--no-cert-store")
.arg("--no-key-store")
.arg("key").arg("adopt")
.arg(bob()) .arg(bob())
.arg("--keyring").arg(alice()) .arg("--keyring").arg(alice())
.arg("--key").arg(alice_signing().0.to_hex()) .arg("--key").arg(alice_signing().0.to_hex())

View File

@ -27,6 +27,7 @@ mod integration {
// Build up the command line. // Build up the command line.
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"key", "generate", "key", "generate",
"--time", iso8601, "--time", iso8601,
"--expiry", "never", "--expiry", "never",

View File

@ -106,6 +106,7 @@ fn sq_key_revoke() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"revoke", "revoke",
"--output", "--output",
@ -278,6 +279,7 @@ fn sq_key_revoke_thirdparty() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"revoke", "revoke",
"--output", "--output",

View File

@ -23,6 +23,7 @@ fn sq_key_subkey_generate_authentication_subkey() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"subkey", "subkey",
"add", "add",
@ -52,6 +53,7 @@ fn sq_key_subkey_generate_encryption_subkey() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"subkey", "subkey",
"add", "add",
@ -91,6 +93,7 @@ fn sq_key_subkey_generate_signing_subkey() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"subkey", "subkey",
"add", "add",
@ -208,6 +211,7 @@ fn sq_key_subkey_revoke() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"subkey", "subkey",
"revoke", "revoke",
@ -406,6 +410,7 @@ fn sq_key_subkey_revoke_thirdparty() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"subkey", "subkey",
"revoke", "revoke",

View File

@ -78,6 +78,7 @@ fn sq_key_userid_revoke() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"userid", "userid",
"revoke", "revoke",
@ -231,6 +232,7 @@ fn sq_key_userid_revoke_thirdparty() -> Result<()> {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.args([ cmd.args([
"--no-cert-store", "--no-cert-store",
"--no-key-store",
"key", "key",
"userid", "userid",
"revoke", "revoke",

View File

@ -60,6 +60,7 @@ fn sq_gen_key(cert_store: Option<&str>, userids: &[&str], file: &str) -> Cert
{ {
let mut cmd = Command::cargo_bin("sq").expect("have sq"); let mut cmd = Command::cargo_bin("sq").expect("have sq");
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"key", "generate", "key", "generate",
"--time", &tick(), "--time", &tick(),
"--expiry", "never", "--expiry", "never",
@ -86,6 +87,7 @@ fn sq_verify(cert_store: Option<&str>,
good_sigs: usize, good_checksums: usize) good_sigs: usize, good_checksums: usize)
{ {
let mut cmd = Command::cargo_bin("sq").expect("have sq"); let mut cmd = Command::cargo_bin("sq").expect("have sq");
cmd.arg("--no-key-store");
if let Some(cert_store) = cert_store { if let Some(cert_store) = cert_store {
cmd.args(&["--cert-store", cert_store]); cmd.args(&["--cert-store", cert_store]);
} else { } else {
@ -270,6 +272,7 @@ fn sq_link_add_retract() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &data.key_file]) .args(["--signer-file", &data.key_file])
.args(["--output", &data.sig_file]) .args(["--output", &data.sig_file])
@ -403,6 +406,7 @@ fn sq_link_add_retract() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &ed_pgp]) .args(["--signer-file", &ed_pgp])
.args(["--output", &ed_sig_file]) .args(["--output", &ed_sig_file])
@ -618,6 +622,7 @@ fn sq_link_add_temporary() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &alice_pgp]) .args(["--signer-file", &alice_pgp])
.args(["--output", &alice_sig_file]) .args(["--output", &alice_sig_file])

View File

@ -20,7 +20,9 @@ mod sq_packet_decrypt {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"]) .args(["--session-key", "1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"])
@ -36,7 +38,9 @@ mod sq_packet_decrypt {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "9:1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"]) .args(["--session-key", "9:1FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"])
@ -52,7 +56,9 @@ mod sq_packet_decrypt {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "2FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"]) .args(["--session-key", "2FE820EC21FB5D7E33D83367106D1D3747DCD48E6320C1AEC57EE7D18FC437D4"])
@ -70,7 +76,9 @@ mod sq_packet_decrypt {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("decrypt") .arg("decrypt")
.args(["--session-key", "BB9CCB8EDE22DC222C83BD1C63AEB97335DDC7B696DB171BD16EAA5784CC0478"]) .args(["--session-key", "BB9CCB8EDE22DC222C83BD1C63AEB97335DDC7B696DB171BD16EAA5784CC0478"])

View File

@ -15,6 +15,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")
@ -31,6 +32,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")
@ -47,6 +49,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")
@ -65,6 +68,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")
@ -78,6 +82,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")
@ -95,6 +100,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")
@ -108,6 +114,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")
@ -124,6 +131,7 @@ mod sq_packet_dump {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("toolbox") .arg("toolbox")
.arg("packet") .arg("packet")
.arg("dump") .arg("dump")

View File

@ -114,6 +114,7 @@ mod integration {
let mut cmd = Command::cargo_bin("sq")?; let mut cmd = Command::cargo_bin("sq")?;
cmd.current_dir(&dir()) cmd.current_dir(&dir())
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.args(&["--output-format", &format!("{}", outputformat)]) .args(&["--output-format", &format!("{}", outputformat)])
.args(&["--keyring", keyring]); .args(&["--keyring", keyring]);
if let Some(trust_root) = trust_root { if let Some(trust_root) = trust_root {

View File

@ -35,6 +35,7 @@ fn sq_sign() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")])
.args(["--output", &sig.to_string_lossy()]) .args(["--output", &sig.to_string_lossy()])
@ -70,6 +71,7 @@ fn sq_sign() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.arg(&*sig.to_string_lossy()) .arg(&*sig.to_string_lossy())
@ -86,6 +88,7 @@ fn sq_sign_with_notations() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")])
.args(["--output", &sig.to_string_lossy()]) .args(["--output", &sig.to_string_lossy()])
@ -149,6 +152,7 @@ fn sq_sign_with_notations() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.args(["--known-notation", "foo"]) .args(["--known-notation", "foo"])
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
@ -166,6 +170,7 @@ fn sq_sign_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")])
.args(["--output", &sig0.to_string_lossy()]) .args(["--output", &sig0.to_string_lossy()])
@ -201,6 +206,7 @@ fn sq_sign_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -212,6 +218,7 @@ fn sq_sign_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--append") .arg("--append")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")])
@ -262,6 +269,7 @@ fn sq_sign_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.arg(&*sig1.to_string_lossy()) .arg(&*sig1.to_string_lossy())
@ -270,6 +278,7 @@ fn sq_sign_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")])
.arg(&*sig1.to_string_lossy()) .arg(&*sig1.to_string_lossy())
@ -332,6 +341,7 @@ fn sq_sign_append_on_compress_then_sign() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -343,6 +353,7 @@ fn sq_sign_append_on_compress_then_sign() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--append") .arg("--append")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")])
@ -396,6 +407,7 @@ fn sq_sign_append_on_compress_then_sign() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -405,6 +417,7 @@ fn sq_sign_append_on_compress_then_sign() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -421,6 +434,7 @@ fn sq_sign_detached() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--detached") .arg("--detached")
.args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")])
@ -446,6 +460,7 @@ fn sq_sign_detached() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.args(["--detached", &sig.to_string_lossy()]) .args(["--detached", &sig.to_string_lossy()])
@ -463,6 +478,7 @@ fn sq_sign_detached_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--detached") .arg("--detached")
.args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton-private.pgp")])
@ -488,6 +504,7 @@ fn sq_sign_detached_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.args(["--detached", &sig.to_string_lossy()]) .args(["--detached", &sig.to_string_lossy()])
@ -499,6 +516,7 @@ fn sq_sign_detached_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--detached") .arg("--detached")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")])
@ -511,6 +529,7 @@ fn sq_sign_detached_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--detached") .arg("--detached")
.arg("--append") .arg("--append")
@ -542,6 +561,7 @@ fn sq_sign_detached_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")]) .args(["--signer-file", &artifact("keys/dennis-simon-anton.pgp")])
.args(["--detached", &sig.to_string_lossy()]) .args(["--detached", &sig.to_string_lossy()])
@ -552,6 +572,7 @@ fn sq_sign_detached_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")])
.args(["--detached", &sig.to_string_lossy()]) .args(["--detached", &sig.to_string_lossy()])
@ -564,6 +585,7 @@ fn sq_sign_detached_append() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--detached") .arg("--detached")
.arg("--append") .arg("--append")
@ -602,6 +624,7 @@ fn sq_sign_append_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--append") .arg("--append")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")])
@ -663,6 +686,7 @@ fn sq_sign_append_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/neal.pgp")]) .args(["--signer-file", &artifact("keys/neal.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -671,6 +695,7 @@ fn sq_sign_append_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp")]) .args(["--signer-file", &artifact("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -679,6 +704,7 @@ fn sq_sign_append_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -696,6 +722,7 @@ fn sq_sign_notarize() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--notarize") .arg("--notarize")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")])
@ -745,6 +772,7 @@ fn sq_sign_notarize() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/neal.pgp")]) .args(["--signer-file", &artifact("keys/neal.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -753,6 +781,7 @@ fn sq_sign_notarize() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -770,6 +799,7 @@ fn sq_sign_notarize_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.arg("--notarize") .arg("--notarize")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256-private.pgp")])
@ -831,6 +861,7 @@ fn sq_sign_notarize_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/neal.pgp")]) .args(["--signer-file", &artifact("keys/neal.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -839,6 +870,7 @@ fn sq_sign_notarize_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp")]) .args(["--signer-file", &artifact("keys/emmelie-dorothea-dina-samantha-awina-ed25519.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -847,6 +879,7 @@ fn sq_sign_notarize_a_notarization() {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")]) .args(["--signer-file", &artifact("keys/erika-corinna-daniela-simone-antonia-nistp256.pgp")])
.arg(&*sig0.to_string_lossy()) .arg(&*sig0.to_string_lossy())
@ -878,7 +911,7 @@ fn sq_multiple_signers() -> Result<()> {
// Sign message. // Sign message.
let assertion = Command::cargo_bin("sq")? let assertion = Command::cargo_bin("sq")?
.args([ .args([
"--no-cert-store", "--no-cert-store", "--no-key-store",
"sign", "sign",
"--signer-file", alice_pgp.to_str().unwrap(), "--signer-file", alice_pgp.to_str().unwrap(),
"--signer-file", &bob_pgp.to_str().unwrap(), "--signer-file", &bob_pgp.to_str().unwrap(),
@ -957,6 +990,7 @@ fn sq_sign_using_cert_store() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &alice_pgp]) .args(["--signer-file", &alice_pgp])
.args(["--output", &msg_pgp]) .args(["--output", &msg_pgp])
@ -998,6 +1032,7 @@ fn sq_sign_using_cert_store() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.args(["--signer-file", &alice_pgp]) .args(["--signer-file", &alice_pgp])
.arg(&msg_pgp) .arg(&msg_pgp)
@ -1008,6 +1043,7 @@ fn sq_sign_using_cert_store() -> Result<()> {
// certificate or use a certificate store. // certificate or use a certificate store.
let mut cmd = Command::cargo_bin("sq").unwrap(); let mut cmd = Command::cargo_bin("sq").unwrap();
cmd.arg("--no-cert-store") cmd.arg("--no-cert-store")
.arg("--no-key-store")
.arg("verify") .arg("verify")
.arg(&msg_pgp); .arg(&msg_pgp);
let output = cmd.output().expect("success"); let output = cmd.output().expect("success");
@ -1098,6 +1134,7 @@ fn sq_verify_wot() -> Result<()> {
{ {
let mut cmd = Command::cargo_bin("sq").expect("have sq"); let mut cmd = Command::cargo_bin("sq").expect("have sq");
cmd.args(["--no-cert-store", cmd.args(["--no-cert-store",
"--no-key-store",
"key", "generate", "key", "generate",
"--expiry", "never", "--expiry", "never",
"--output", file]); "--output", file]);
@ -1120,6 +1157,7 @@ fn sq_verify_wot() -> Result<()> {
msg_pgp: &str| msg_pgp: &str|
{ {
let mut cmd = Command::cargo_bin("sq").expect("have sq"); let mut cmd = Command::cargo_bin("sq").expect("have sq");
cmd.arg("--no-key-store");
if let Some(cert_store) = cert_store { if let Some(cert_store) = cert_store {
cmd.args(&["--cert-store", cert_store]); cmd.args(&["--cert-store", cert_store]);
} else { } else {
@ -1186,6 +1224,7 @@ fn sq_verify_wot() -> Result<()> {
Command::cargo_bin("sq") Command::cargo_bin("sq")
.unwrap() .unwrap()
.arg("--no-cert-store") .arg("--no-cert-store")
.arg("--no-key-store")
.arg("sign") .arg("sign")
.args(["--signer-file", &bob_pgp]) .args(["--signer-file", &bob_pgp])
.args(["--signer-file", &carol_pgp]) .args(["--signer-file", &carol_pgp])