From 726b62b3f4165a5e66600265cf96b5b7475a1345 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 3 Nov 2023 20:58:51 -0500 Subject: [PATCH] keyfork-shard: make recovery file required, key discovery optional --- .../src/bin/keyfork-shard-combine-openpgp.rs | 35 ++++++++----------- .../src/bin/keyfork-shard/openpgp/combine.md | 8 ++--- keyfork/src/cli/shard.rs | 14 ++++++-- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/keyfork-shard/src/bin/keyfork-shard-combine-openpgp.rs b/keyfork-shard/src/bin/keyfork-shard-combine-openpgp.rs index cead655..32b6c02 100644 --- a/keyfork-shard/src/bin/keyfork-shard-combine-openpgp.rs +++ b/keyfork-shard/src/bin/keyfork-shard-combine-openpgp.rs @@ -1,7 +1,7 @@ use std::{ env, fs::File, - io::{stdin, stdout}, + io::stdout, path::PathBuf, process::ExitCode, str::FromStr, @@ -11,27 +11,22 @@ use keyfork_shard::openpgp::{combine, discover_certs, openpgp::Cert, parse_messa type Result> = std::result::Result; -fn validate( +fn validate<'a>( threshold: &str, - key_discovery: &str, recovery_file: &str, + key_discovery: impl Into>, ) -> Result<(u8, Vec, PathBuf)> { let threshold = u8::from_str(threshold)?; - let key_discovery = PathBuf::from(key_discovery); - - // Verify path exists - std::fs::metadata(&key_discovery)?; + let key_discovery = key_discovery.into().map(PathBuf::from); + key_discovery.as_ref().map(std::fs::metadata).transpose()?; // Load certs from path - let certs = discover_certs(key_discovery)?; - - let recovery_file = PathBuf::from(if recovery_file == "-" { - eprintln!("loading certs from stdin; note that prompting smartcard PINs will not work"); - "/dev/stdin" - } else { - recovery_file - }); + let certs = key_discovery + .map(discover_certs) + .transpose()? + .unwrap_or(vec![]); + let recovery_file = PathBuf::from(recovery_file); std::fs::metadata(&recovery_file)?; Ok((threshold, certs, recovery_file)) @@ -42,13 +37,11 @@ fn run() -> Result<()> { let program_name = args.next().expect("program name"); let args = args.collect::>(); let (threshold, cert_list, recovery_file) = match args.as_slice() { - [threshold, key_discovery, recovery_file] => { - validate(threshold, key_discovery, recovery_file)? + [threshold, recovery_file, key_discovery] => { + validate(threshold, recovery_file, key_discovery.as_str())? } - [threshold, key_discovery] => { - validate(threshold, key_discovery, "-")? - } - _ => panic!("Usage: {program_name} threshold key_discovery recovery_file"), + [threshold, recovery_file] => validate(threshold, recovery_file, None)?, + _ => panic!("Usage: {program_name} threshold recovery_file [key_discovery]"), }; let mut encrypted_messages = parse_messages(File::open(recovery_file)?)?; diff --git a/keyfork-user-guide/src/bin/keyfork-shard/openpgp/combine.md b/keyfork-user-guide/src/bin/keyfork-shard/openpgp/combine.md index 5c12274..b3c9220 100644 --- a/keyfork-user-guide/src/bin/keyfork-shard/openpgp/combine.md +++ b/keyfork-user-guide/src/bin/keyfork-shard/openpgp/combine.md @@ -8,16 +8,14 @@ Combine `threshold` shares into a previously [`split`] secret. * `threshold`: Minimum number of operators present to recover the secret, as previously configured when creating the secret -* `key_discovery`: Either a file or a directory containing OpenPGP keys. - If a file, load all keys from the file. - If a directory, for every file in the directory (non-recursively), load - keys from the file. +* `recovery_file`: File of OpenPGP Messages from [`split`]. +* `key_discovery`: A directory containing OpenPGP keys. If the amount of keys found is less than `threshold`, an OpenPGP Card fallback will be used to decrypt the rest of the messages. ## Input -OpenPGP Messages from [`split`]. +When required by OpenPGP cards, a prompt will be presented for PIN entry. ## Output diff --git a/keyfork/src/cli/shard.rs b/keyfork/src/cli/shard.rs index 9337082..1a36d5f 100644 --- a/keyfork/src/cli/shard.rs +++ b/keyfork/src/cli/shard.rs @@ -1,6 +1,7 @@ use super::Keyfork; use clap::{builder::PossibleValue, Parser, Subcommand, ValueEnum}; use std::{ + fs::File, io::{stdin, stdout, BufRead, BufReader, Read, Write}, path::{Path, PathBuf}, }; @@ -135,6 +136,9 @@ pub enum ShardSubcommands { #[arg(long)] threshold: u8, + /// The path to load the encrypted shares from. + recovery_file: PathBuf, + /// The path to discover private keys from. key_discovery: Option, }, @@ -171,11 +175,15 @@ impl ShardSubcommands { } ShardSubcommands::Combine { threshold, + recovery_file, key_discovery, } => match &shard.format { - Some(Format::OpenPGP(o)) => { - o.combine(*threshold, key_discovery.as_ref(), stdin, &mut stdout) - } + Some(Format::OpenPGP(o)) => o.combine( + *threshold, + key_discovery.as_ref(), + File::open(recovery_file)?, + &mut stdout, + ), Some(Format::P256(_p)) => { todo!() }