keyfork-shard: make recovery file required, key discovery optional
This commit is contained in:
parent
5b427516c6
commit
726b62b3f4
|
@ -1,7 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{stdin, stdout},
|
io::stdout,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
@ -11,27 +11,22 @@ use keyfork_shard::openpgp::{combine, discover_certs, openpgp::Cert, parse_messa
|
||||||
|
|
||||||
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||||
|
|
||||||
fn validate(
|
fn validate<'a>(
|
||||||
threshold: &str,
|
threshold: &str,
|
||||||
key_discovery: &str,
|
|
||||||
recovery_file: &str,
|
recovery_file: &str,
|
||||||
|
key_discovery: impl Into<Option<&'a str>>,
|
||||||
) -> Result<(u8, Vec<Cert>, PathBuf)> {
|
) -> Result<(u8, Vec<Cert>, PathBuf)> {
|
||||||
let threshold = u8::from_str(threshold)?;
|
let threshold = u8::from_str(threshold)?;
|
||||||
let key_discovery = PathBuf::from(key_discovery);
|
let key_discovery = key_discovery.into().map(PathBuf::from);
|
||||||
|
key_discovery.as_ref().map(std::fs::metadata).transpose()?;
|
||||||
// Verify path exists
|
|
||||||
std::fs::metadata(&key_discovery)?;
|
|
||||||
|
|
||||||
// Load certs from path
|
// Load certs from path
|
||||||
let certs = discover_certs(key_discovery)?;
|
let certs = key_discovery
|
||||||
|
.map(discover_certs)
|
||||||
let recovery_file = PathBuf::from(if recovery_file == "-" {
|
.transpose()?
|
||||||
eprintln!("loading certs from stdin; note that prompting smartcard PINs will not work");
|
.unwrap_or(vec![]);
|
||||||
"/dev/stdin"
|
|
||||||
} else {
|
|
||||||
recovery_file
|
|
||||||
});
|
|
||||||
|
|
||||||
|
let recovery_file = PathBuf::from(recovery_file);
|
||||||
std::fs::metadata(&recovery_file)?;
|
std::fs::metadata(&recovery_file)?;
|
||||||
|
|
||||||
Ok((threshold, certs, recovery_file))
|
Ok((threshold, certs, recovery_file))
|
||||||
|
@ -42,13 +37,11 @@ fn run() -> Result<()> {
|
||||||
let program_name = args.next().expect("program name");
|
let program_name = args.next().expect("program name");
|
||||||
let args = args.collect::<Vec<_>>();
|
let args = args.collect::<Vec<_>>();
|
||||||
let (threshold, cert_list, recovery_file) = match args.as_slice() {
|
let (threshold, cert_list, recovery_file) = match args.as_slice() {
|
||||||
[threshold, key_discovery, recovery_file] => {
|
[threshold, recovery_file, key_discovery] => {
|
||||||
validate(threshold, key_discovery, recovery_file)?
|
validate(threshold, recovery_file, key_discovery.as_str())?
|
||||||
}
|
}
|
||||||
[threshold, key_discovery] => {
|
[threshold, recovery_file] => validate(threshold, recovery_file, None)?,
|
||||||
validate(threshold, key_discovery, "-")?
|
_ => panic!("Usage: {program_name} threshold recovery_file [key_discovery]"),
|
||||||
}
|
|
||||||
_ => panic!("Usage: {program_name} threshold key_discovery recovery_file"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut encrypted_messages = parse_messages(File::open(recovery_file)?)?;
|
let mut encrypted_messages = parse_messages(File::open(recovery_file)?)?;
|
||||||
|
|
|
@ -8,16 +8,14 @@ Combine `threshold` shares into a previously [`split`] secret.
|
||||||
|
|
||||||
* `threshold`: Minimum number of operators present to recover the secret, as
|
* `threshold`: Minimum number of operators present to recover the secret, as
|
||||||
previously configured when creating the secret
|
previously configured when creating the secret
|
||||||
* `key_discovery`: Either a file or a directory containing OpenPGP keys.
|
* `recovery_file`: File of OpenPGP Messages from [`split`].
|
||||||
If a file, load all keys from the file.
|
* `key_discovery`: A directory containing OpenPGP keys.
|
||||||
If a directory, for every file in the directory (non-recursively), load
|
|
||||||
keys from the file.
|
|
||||||
If the amount of keys found is less than `threshold`, an OpenPGP Card
|
If the amount of keys found is less than `threshold`, an OpenPGP Card
|
||||||
fallback will be used to decrypt the rest of the messages.
|
fallback will be used to decrypt the rest of the messages.
|
||||||
|
|
||||||
## Input
|
## Input
|
||||||
|
|
||||||
OpenPGP Messages from [`split`].
|
When required by OpenPGP cards, a prompt will be presented for PIN entry.
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::Keyfork;
|
use super::Keyfork;
|
||||||
use clap::{builder::PossibleValue, Parser, Subcommand, ValueEnum};
|
use clap::{builder::PossibleValue, Parser, Subcommand, ValueEnum};
|
||||||
use std::{
|
use std::{
|
||||||
|
fs::File,
|
||||||
io::{stdin, stdout, BufRead, BufReader, Read, Write},
|
io::{stdin, stdout, BufRead, BufReader, Read, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
@ -135,6 +136,9 @@ pub enum ShardSubcommands {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
threshold: u8,
|
threshold: u8,
|
||||||
|
|
||||||
|
/// The path to load the encrypted shares from.
|
||||||
|
recovery_file: PathBuf,
|
||||||
|
|
||||||
/// The path to discover private keys from.
|
/// The path to discover private keys from.
|
||||||
key_discovery: Option<PathBuf>,
|
key_discovery: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
@ -171,11 +175,15 @@ impl ShardSubcommands {
|
||||||
}
|
}
|
||||||
ShardSubcommands::Combine {
|
ShardSubcommands::Combine {
|
||||||
threshold,
|
threshold,
|
||||||
|
recovery_file,
|
||||||
key_discovery,
|
key_discovery,
|
||||||
} => match &shard.format {
|
} => match &shard.format {
|
||||||
Some(Format::OpenPGP(o)) => {
|
Some(Format::OpenPGP(o)) => o.combine(
|
||||||
o.combine(*threshold, key_discovery.as_ref(), stdin, &mut stdout)
|
*threshold,
|
||||||
}
|
key_discovery.as_ref(),
|
||||||
|
File::open(recovery_file)?,
|
||||||
|
&mut stdout,
|
||||||
|
),
|
||||||
Some(Format::P256(_p)) => {
|
Some(Format::P256(_p)) => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue