keyfork: restructure wizard shard key generation
also: `keyfork provision shard`
This commit is contained in:
parent
674e2e93c5
commit
a1c3d52c14
|
@ -12,20 +12,27 @@ type Identifier = (String, Option<String>);
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum Provisioner {
|
||||
OpenPGPCard(openpgp::OpenPGPCard),
|
||||
Shard(openpgp::Shard),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Provisioner {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Provisioner::OpenPGPCard(_) => f.write_str("openpgp-card"),
|
||||
}
|
||||
f.write_str(self.identifier())
|
||||
}
|
||||
}
|
||||
|
||||
impl Provisioner {
|
||||
pub fn identifier(&self) -> &'static str {
|
||||
match self {
|
||||
Provisioner::OpenPGPCard(_) => "openpgp-card",
|
||||
Provisioner::Shard(_) => "shard",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn discover(&self) -> Result<Vec<Identifier>, Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Provisioner::OpenPGPCard(o) => o.discover(),
|
||||
Provisioner::Shard(s) => s.discover(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,6 +51,17 @@ impl Provisioner {
|
|||
let xprv: XPrv = client.request_xprv(&path)?;
|
||||
o.provision(xprv, provisioner)
|
||||
}
|
||||
Provisioner::Shard(s) => {
|
||||
type Prv = <openpgp::Shard as ProvisionExec>::PrivateKey;
|
||||
type XPrv = ExtendedPrivateKey<Prv>;
|
||||
let account_index = DerivationIndex::new(provisioner.account, true)?;
|
||||
let path = <openpgp::Shard as ProvisionExec>::derivation_prefix()
|
||||
.chain_push(account_index);
|
||||
let mut client = keyforkd_client::Client::discover_socket()?;
|
||||
let xprv: XPrv = client.request_xprv(&path)?;
|
||||
panic!();
|
||||
s.provision(xprv, provisioner)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,19 +80,26 @@ impl Provisioner {
|
|||
let xprv = XPrv::new(mnemonic.generate_seed(None))?.derive_path(&path)?;
|
||||
o.provision(xprv, provisioner)
|
||||
}
|
||||
Provisioner::Shard(s) => {
|
||||
type Prv = <openpgp::Shard as ProvisionExec>::PrivateKey;
|
||||
type XPrv = ExtendedPrivateKey<Prv>;
|
||||
let account_index = DerivationIndex::new(provisioner.account, true)?;
|
||||
let path = <openpgp::Shard as ProvisionExec>::derivation_prefix()
|
||||
.chain_push(account_index);
|
||||
let xprv = XPrv::new(mnemonic.generate_seed(None))?.derive_path(&path)?;
|
||||
s.provision(xprv, provisioner)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueEnum for Provisioner {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
&[Self::OpenPGPCard(openpgp::OpenPGPCard)]
|
||||
&[Self::OpenPGPCard(openpgp::OpenPGPCard), Self::Shard(openpgp::Shard)]
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(PossibleValue::new(match self {
|
||||
Self::OpenPGPCard(_) => "openpgp-card",
|
||||
}))
|
||||
Some(PossibleValue::new(self.identifier()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,17 +18,11 @@ use keyfork_prompt::default_handler;
|
|||
use openpgp_card_sequoia::{state::Open, Card};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OpenPGPCard;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
#[error("Provisioner was unable to find a matching smartcard")]
|
||||
struct NoMatchingSmartcard;
|
||||
|
||||
impl ProvisionExec for OpenPGPCard {
|
||||
type PrivateKey = keyfork_derive_openpgp::XPrvKey;
|
||||
|
||||
fn discover(&self) -> Result<Vec<(String, Option<String>)>, Box<dyn std::error::Error>> {
|
||||
fn discover_cards() -> Result<Vec<(String, Option<String>)>, Box<dyn std::error::Error>> {
|
||||
let mut idents = vec![];
|
||||
for backend in PcscBackend::cards(None)? {
|
||||
let backend = backend?;
|
||||
|
@ -42,14 +36,9 @@ impl ProvisionExec for OpenPGPCard {
|
|||
Ok(idents)
|
||||
}
|
||||
|
||||
fn derivation_prefix() -> keyfork_derive_util::DerivationPath {
|
||||
keyfork_derive_path_data::paths::OPENPGP.clone()
|
||||
}
|
||||
|
||||
fn provision(
|
||||
&self,
|
||||
xprv: XPrv,
|
||||
fn provision_card(
|
||||
provisioner: config::Provisioner,
|
||||
xprv: XPrv,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut pm = default_handler()?;
|
||||
|
||||
|
@ -116,4 +105,49 @@ impl ProvisionExec for OpenPGPCard {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OpenPGPCard;
|
||||
|
||||
impl ProvisionExec for OpenPGPCard {
|
||||
type PrivateKey = keyfork_derive_openpgp::XPrvKey;
|
||||
|
||||
fn discover(&self) -> Result<Vec<(String, Option<String>)>, Box<dyn std::error::Error>> {
|
||||
discover_cards()
|
||||
}
|
||||
|
||||
fn derivation_prefix() -> keyfork_derive_util::DerivationPath {
|
||||
keyfork_derive_path_data::paths::OPENPGP.clone()
|
||||
}
|
||||
|
||||
fn provision(
|
||||
&self,
|
||||
xprv: XPrv,
|
||||
provisioner: config::Provisioner,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
provision_card(provisioner, xprv)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Shard;
|
||||
|
||||
impl ProvisionExec for Shard {
|
||||
type PrivateKey = keyfork_derive_openpgp::XPrvKey;
|
||||
|
||||
fn discover(&self) -> Result<Vec<(String, Option<String>)>, Box<dyn std::error::Error>> {
|
||||
discover_cards()
|
||||
}
|
||||
|
||||
fn derivation_prefix() -> keyfork_derive_util::DerivationPath {
|
||||
keyfork_derive_path_data::paths::OPENPGP_SHARD.clone()
|
||||
}
|
||||
|
||||
fn provision(
|
||||
&self,
|
||||
xprv: XPrv,
|
||||
provisioner: config::Provisioner,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
provision_card(provisioner, xprv)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,7 @@ pub struct PinLength(usize);
|
|||
|
||||
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||
|
||||
// TODO: refactor to use mnemonic derived seed instead of 256 bit entropy to allow for possible
|
||||
// recovery in the future.
|
||||
fn derive_key(seed: [u8; 32], index: u8) -> Result<Cert> {
|
||||
fn derive_key(seed: [u8; 64], index: u8) -> Result<Cert> {
|
||||
let subkeys = vec![
|
||||
KeyFlags::empty().set_certification(),
|
||||
KeyFlags::empty().set_signing(),
|
||||
|
@ -167,7 +165,9 @@ fn cross_sign_certs(certs: &mut [Cert]) -> Result<(), Box<dyn std::error::Error>
|
|||
|
||||
impl GenerateShardSecret {
|
||||
fn handle(&self) -> Result<()> {
|
||||
let seed = keyfork_entropy::generate_entropy_of_const_size::<{ 256 / 8 }>()?;
|
||||
let root_entropy = keyfork_entropy::generate_entropy_of_const_size::<{ 256 / 8 }>()?;
|
||||
let mnemonic = Mnemonic::from_array(root_entropy);
|
||||
let seed = mnemonic.generate_seed(None);
|
||||
let mut pm = default_handler()?;
|
||||
let mut certs = vec![];
|
||||
let mut seen_cards: HashSet<String> = HashSet::new();
|
||||
|
@ -246,12 +246,18 @@ impl GenerateShardSecret {
|
|||
|
||||
if let Some(output_file) = self.output.as_ref() {
|
||||
let output = File::create(output_file)?;
|
||||
opgp.shard_and_encrypt(self.threshold, certs.len() as u8, &seed, &certs[..], output)?;
|
||||
opgp.shard_and_encrypt(
|
||||
self.threshold,
|
||||
certs.len() as u8,
|
||||
mnemonic.as_bytes(),
|
||||
&certs[..],
|
||||
output,
|
||||
)?;
|
||||
} else {
|
||||
opgp.shard_and_encrypt(
|
||||
self.threshold,
|
||||
certs.len() as u8,
|
||||
&seed,
|
||||
mnemonic.as_bytes(),
|
||||
&certs[..],
|
||||
std::io::stdout(),
|
||||
)?;
|
||||
|
|
Loading…
Reference in New Issue