keyfork: add `bottoms-up` wizard
This commit is contained in:
parent
142bea3b9f
commit
d5c3587343
|
@ -83,7 +83,7 @@ fn validate(
|
||||||
let index = DerivationIndex::new(u32::from_be_bytes(pgp_u32), true)?;
|
let index = DerivationIndex::new(u32::from_be_bytes(pgp_u32), true)?;
|
||||||
|
|
||||||
let path = DerivationPath::from_str(path)?;
|
let path = DerivationPath::from_str(path)?;
|
||||||
assert_eq!(2, path.len(), "Expected path of m/{index}/account_id'");
|
assert!(path.len() >= 2, "Expected path of at least m/{index}/account_id'");
|
||||||
|
|
||||||
let given_index = path.iter().next().expect("checked .len() above");
|
let given_index = path.iter().next().expect("checked .len() above");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use super::Keyfork;
|
use super::Keyfork;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use std::{collections::HashSet, fs::File, io::IsTerminal, path::PathBuf};
|
use std::{
|
||||||
|
collections::HashSet,
|
||||||
|
fs::File,
|
||||||
|
io::IsTerminal,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
use card_backend_pcsc::PcscBackend;
|
use card_backend_pcsc::PcscBackend;
|
||||||
use openpgp_card_sequoia::{state::Open, types::KeyType, Card};
|
use openpgp_card_sequoia::{state::Open, types::KeyType, Card};
|
||||||
|
@ -185,6 +190,35 @@ fn generate_shard_secret(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bottoms_up(key_discovery: &Path, threshold: u8, output: &Option<PathBuf>) -> Result<()> {
|
||||||
|
let seed = keyfork_entropy::generate_entropy_of_const_size::<{ 256 / 8 }>()?;
|
||||||
|
let stdout = std::io::stdout();
|
||||||
|
if output.is_none() {
|
||||||
|
assert!(
|
||||||
|
!stdout.is_terminal(),
|
||||||
|
"not printing shard to terminal, redirect output"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let opgp = OpenPGP::<DefaultTerminal>::new();
|
||||||
|
let certs = OpenPGP::<DefaultTerminal>::discover_certs(key_discovery)?;
|
||||||
|
|
||||||
|
if let Some(output_file) = output {
|
||||||
|
let output = File::create(output_file)?;
|
||||||
|
opgp.shard_and_encrypt(threshold, certs.len() as u8, &seed, &certs[..], output)?;
|
||||||
|
} else {
|
||||||
|
opgp.shard_and_encrypt(
|
||||||
|
threshold,
|
||||||
|
certs.len() as u8,
|
||||||
|
&seed,
|
||||||
|
&certs[..],
|
||||||
|
std::io::stdout(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Subcommand, Clone, Debug)]
|
#[derive(Subcommand, Clone, Debug)]
|
||||||
pub enum WizardSubcommands {
|
pub enum WizardSubcommands {
|
||||||
/// Create a 256 bit secret and shard the secret to smart cards.
|
/// Create a 256 bit secret and shard the secret to smart cards.
|
||||||
|
@ -209,6 +243,24 @@ pub enum WizardSubcommands {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
output: Option<PathBuf>,
|
output: Option<PathBuf>,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Create a 256 bit secret and shard the secret to previously known OpenPGP certificates,
|
||||||
|
/// deriving the default OpenPGP certificate for the secret.
|
||||||
|
///
|
||||||
|
/// This command was purpose-built for DEFCON and is not intended to be used normally, as it
|
||||||
|
/// implies keys used for sharding have been generated by a custom source.
|
||||||
|
BottomsUp {
|
||||||
|
/// The location of OpenPGP certificates to use when sharding.
|
||||||
|
key_discovery: PathBuf,
|
||||||
|
|
||||||
|
/// The minimum amount of keys required to decrypt the secret.
|
||||||
|
#[arg(long)]
|
||||||
|
threshold: u8,
|
||||||
|
|
||||||
|
/// The file to write the generated shard file to.
|
||||||
|
#[arg(long)]
|
||||||
|
output: Option<PathBuf>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WizardSubcommands {
|
impl WizardSubcommands {
|
||||||
|
@ -220,6 +272,11 @@ impl WizardSubcommands {
|
||||||
keys_per_shard,
|
keys_per_shard,
|
||||||
output,
|
output,
|
||||||
} => generate_shard_secret(*threshold, *max, *keys_per_shard, output),
|
} => generate_shard_secret(*threshold, *max, *keys_per_shard, output),
|
||||||
|
WizardSubcommands::BottomsUp {
|
||||||
|
key_discovery,
|
||||||
|
threshold,
|
||||||
|
output,
|
||||||
|
} => bottoms_up(key_discovery, *threshold, output),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue