keyfork{,-shard}: make all shard-accepting commandsz take it as an argument, not stdin
This commit is contained in:
parent
dd3ffe74b3
commit
ceb0ac2455
|
@ -1,7 +1,7 @@
|
|||
use std::{
|
||||
env,
|
||||
io::stdin,
|
||||
path::PathBuf,
|
||||
fs::File,
|
||||
path::{Path, PathBuf},
|
||||
process::ExitCode,
|
||||
};
|
||||
|
||||
|
@ -9,10 +9,11 @@ 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>;
|
||||
|
||||
fn validate<'a>(
|
||||
key_discovery: impl Into<Option<&'a str>>,
|
||||
) -> Result<Vec<Cert>> {
|
||||
let key_discovery = key_discovery.into().map(PathBuf::from);
|
||||
fn validate(
|
||||
shard: impl AsRef<Path>,
|
||||
key_discovery: Option<&str>,
|
||||
) -> Result<(File, Vec<Cert>)> {
|
||||
let key_discovery = key_discovery.map(PathBuf::from);
|
||||
key_discovery.as_ref().map(std::fs::metadata).transpose()?;
|
||||
|
||||
// Load certs from path
|
||||
|
@ -21,20 +22,20 @@ fn validate<'a>(
|
|||
.transpose()?
|
||||
.unwrap_or(vec![]);
|
||||
|
||||
Ok(certs)
|
||||
Ok((File::open(shard)?, certs))
|
||||
}
|
||||
|
||||
fn run() -> Result<()> {
|
||||
let mut args = env::args();
|
||||
let program_name = args.next().expect("program name");
|
||||
let args = args.collect::<Vec<_>>();
|
||||
let cert_list = match args.as_slice() {
|
||||
[key_discovery] => validate(key_discovery.as_str())?,
|
||||
[] => validate(None)?,
|
||||
_ => panic!("Usage: {program_name} threshold [key_discovery]"),
|
||||
let (messages_file, cert_list) = match args.as_slice() {
|
||||
[shard, key_discovery] => validate(shard, Some(key_discovery))?,
|
||||
[shard] => validate(shard, None)?,
|
||||
_ => panic!("Usage: {program_name} <shard> [key_discovery]"),
|
||||
};
|
||||
|
||||
let mut encrypted_messages = parse_messages(stdin())?;
|
||||
let mut encrypted_messages = parse_messages(messages_file)?;
|
||||
|
||||
let encrypted_metadata = encrypted_messages
|
||||
.pop_front()
|
||||
|
|
|
@ -4,8 +4,9 @@ Combine `threshold` shares into a previously [`split`] secret.
|
|||
|
||||
## Arguments
|
||||
|
||||
`keyfork-shard-combine-openpgp [key_discovery]`
|
||||
`keyfork-shard-combine-openpgp <shard> [key_discovery]`
|
||||
|
||||
* `shard`: The shard file to read from.
|
||||
* `key_discovery`: A file or directory containing OpenPGP keys.
|
||||
If the number of keys found is less than `threshold`, an OpenPGP Card
|
||||
fallback will be used to decrypt the rest of the messages.
|
||||
|
@ -17,10 +18,6 @@ The terminal may be overridden if the default pinentry command is
|
|||
used if an OpenPGP key file has an encrypted secret key or to prompt for the
|
||||
PIN for an OpenPGP smart card.
|
||||
|
||||
## Input
|
||||
|
||||
OpenPGP messages from [`split`].
|
||||
|
||||
## Output
|
||||
|
||||
Hex-encoded secret.
|
||||
|
@ -29,10 +26,10 @@ Hex-encoded secret.
|
|||
|
||||
```sh
|
||||
# Decrypt using only smartcards
|
||||
keyfork-shard-combine-openpgp < shard.pgp
|
||||
keyfork-shard-combine-openpgp shard.pgp
|
||||
|
||||
# Decrypt using on-disk private keys
|
||||
keyfork-shard-combine-openpgp key_discovery.pgp < shard.pgp
|
||||
keyfork-shard-combine-openpgp key_discovery.pgp shard.pgp
|
||||
```
|
||||
|
||||
[`split`]: ./split.md
|
||||
|
|
|
@ -68,8 +68,9 @@ Combine `threshold` shares into a secret.
|
|||
|
||||
### Arguments
|
||||
|
||||
`keyfork shard combine [key_discovery]`
|
||||
`keyfork shard combine <shard> [key_discovery]`
|
||||
|
||||
* `shard`: A file containing the encrypted shards.
|
||||
* `key_discovery`: Either a file or a directory containing public keys.
|
||||
If a file, load all private keys from a file.
|
||||
If a directory, for every file in the directory (non-recursively), load
|
||||
|
@ -77,11 +78,6 @@ Combine `threshold` shares into a secret.
|
|||
If the amount of keys found is less than `threshold`, it is up to the format
|
||||
to determine how to discover the keys.
|
||||
|
||||
### Input
|
||||
|
||||
The input of the command is dependent on the format, but should be the exact
|
||||
same as the output from the `split` command previously used.
|
||||
|
||||
### Output
|
||||
|
||||
Hex-encoded secret.
|
||||
|
@ -106,8 +102,9 @@ by a remote recovery operator.
|
|||
|
||||
### Arguments
|
||||
|
||||
`keyfork shard transport [key_discovery]`
|
||||
`keyfork shard transport <shard> [key_discovery]`
|
||||
|
||||
* `shard`: A file containing encrypted shards.
|
||||
* `key_discovery`: Either a file or a directory containing public keys.
|
||||
If a file, load all private keys from a file.
|
||||
If a directory, for every file in the directory (non-recursively), load
|
||||
|
@ -115,11 +112,6 @@ by a remote recovery operator.
|
|||
If the amount of keys found is less than `threshold`, it is up to the format
|
||||
to determine how to discover the keys.
|
||||
|
||||
### Input
|
||||
|
||||
The input of the command is dependent on the format, but should be the exact
|
||||
same as the output from the `split` command previously used.
|
||||
|
||||
### Prompts
|
||||
|
||||
The command will prompt for 33 words from the remote shard recovery operator,
|
||||
|
@ -131,10 +123,10 @@ operator.
|
|||
|
||||
```sh
|
||||
# Transport using a smart card
|
||||
keyfork shard transport < shard.pgp
|
||||
keyfork shard transport shard.pgp
|
||||
|
||||
# Transport using on-disk private keys
|
||||
keyfork shard transport key_discovery.pgp < shard.pgp
|
||||
keyfork shard transport key_discovery.pgp shard.pgp
|
||||
```
|
||||
|
||||
[`keyfork recover remote-shard`]: ../recover/index.md#keyfork-recover-remote-shard
|
||||
|
|
|
@ -164,6 +164,9 @@ pub enum ShardSubcommands {
|
|||
/// Decrypt a single share and re-encrypt it to an ephemeral symmetric key using mnemonic-based
|
||||
/// prompts. The mnemonics can be sent over insecure channels.
|
||||
Transport {
|
||||
/// The path to load the shard from.
|
||||
shard: PathBuf,
|
||||
|
||||
/// The path to discover private keys from.
|
||||
key_discovery: Option<PathBuf>,
|
||||
},
|
||||
|
@ -175,6 +178,9 @@ pub enum ShardSubcommands {
|
|||
/// hardware metadata discovery, any hardware key used to split may be used to decrypt metadata
|
||||
/// used to combine.
|
||||
Combine {
|
||||
/// The path to load the shards from.
|
||||
shard: PathBuf,
|
||||
|
||||
/// The path to discover private keys from.
|
||||
key_discovery: Option<PathBuf>,
|
||||
},
|
||||
|
@ -186,21 +192,16 @@ impl ShardSubcommands {
|
|||
shard: &Shard,
|
||||
_keyfork: &Keyfork,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut stdin = stdin();
|
||||
let stdin = stdin();
|
||||
let mut stdout = stdout();
|
||||
let mut input = String::new();
|
||||
stdin.read_to_string(&mut input)?;
|
||||
let mut format = shard.format.clone();
|
||||
// bang sandwich macro fun
|
||||
if input.contains("BEGIN PGP MESSAGE") && !matches!(self, ShardSubcommands::Split { .. }) {
|
||||
let _ = format.insert(Format::OpenPGP(OpenPGP));
|
||||
}
|
||||
match self {
|
||||
ShardSubcommands::Split {
|
||||
threshold,
|
||||
max,
|
||||
key_discovery,
|
||||
} => {
|
||||
let input = std::io::read_to_string(stdin)?;
|
||||
assert!(threshold <= max, "threshold {threshold} <= max {max}");
|
||||
let secret = smex::decode(input.trim())?;
|
||||
match format {
|
||||
|
@ -213,20 +214,44 @@ impl ShardSubcommands {
|
|||
None => panic!("{COULD_NOT_DETERMINE_FORMAT}"),
|
||||
}
|
||||
}
|
||||
ShardSubcommands::Transport { key_discovery } => match format {
|
||||
Some(Format::OpenPGP(o)) => o.decrypt(key_discovery.as_ref(), input.as_bytes()),
|
||||
ShardSubcommands::Transport {
|
||||
shard,
|
||||
key_discovery,
|
||||
} => {
|
||||
let shard_content = std::fs::read_to_string(shard)?;
|
||||
if shard_content.contains("BEGIN PGP MESSAGE") {
|
||||
let _ = format.insert(Format::OpenPGP(OpenPGP));
|
||||
}
|
||||
|
||||
match format {
|
||||
Some(Format::OpenPGP(o)) => {
|
||||
o.decrypt(key_discovery.as_ref(), shard_content.as_bytes())
|
||||
}
|
||||
Some(Format::P256(_p)) => todo!(),
|
||||
None => panic!("{COULD_NOT_DETERMINE_FORMAT}"),
|
||||
},
|
||||
ShardSubcommands::Combine { key_discovery } => match format {
|
||||
Some(Format::OpenPGP(o)) => {
|
||||
o.combine(key_discovery.as_ref(), input.as_bytes(), &mut stdout)
|
||||
}
|
||||
}
|
||||
ShardSubcommands::Combine {
|
||||
shard,
|
||||
key_discovery,
|
||||
} => {
|
||||
let shard_content = std::fs::read_to_string(shard)?;
|
||||
if shard_content.contains("BEGIN PGP MESSAGE") {
|
||||
let _ = format.insert(Format::OpenPGP(OpenPGP));
|
||||
}
|
||||
|
||||
match format {
|
||||
Some(Format::OpenPGP(o)) => o.combine(
|
||||
key_discovery.as_ref(),
|
||||
shard_content.as_bytes(),
|
||||
&mut stdout,
|
||||
),
|
||||
Some(Format::P256(_p)) => {
|
||||
todo!()
|
||||
}
|
||||
None => panic!("{COULD_NOT_DETERMINE_FORMAT}"),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue