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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Provisioner {
|
pub enum Provisioner {
|
||||||
OpenPGPCard(openpgp::OpenPGPCard),
|
OpenPGPCard(openpgp::OpenPGPCard),
|
||||||
|
Shard(openpgp::Shard),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Provisioner {
|
impl std::fmt::Display for Provisioner {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
f.write_str(self.identifier())
|
||||||
Provisioner::OpenPGPCard(_) => f.write_str("openpgp-card"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Provisioner {
|
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>> {
|
pub fn discover(&self) -> Result<Vec<Identifier>, Box<dyn std::error::Error>> {
|
||||||
match self {
|
match self {
|
||||||
Provisioner::OpenPGPCard(o) => o.discover(),
|
Provisioner::OpenPGPCard(o) => o.discover(),
|
||||||
|
Provisioner::Shard(s) => s.discover(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +51,17 @@ impl Provisioner {
|
||||||
let xprv: XPrv = client.request_xprv(&path)?;
|
let xprv: XPrv = client.request_xprv(&path)?;
|
||||||
o.provision(xprv, provisioner)
|
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)?;
|
let xprv = XPrv::new(mnemonic.generate_seed(None))?.derive_path(&path)?;
|
||||||
o.provision(xprv, provisioner)
|
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 {
|
impl ValueEnum for Provisioner {
|
||||||
fn value_variants<'a>() -> &'a [Self] {
|
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> {
|
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||||
Some(PossibleValue::new(match self {
|
Some(PossibleValue::new(self.identifier()))
|
||||||
Self::OpenPGPCard(_) => "openpgp-card",
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,17 +18,11 @@ use keyfork_prompt::default_handler;
|
||||||
use openpgp_card_sequoia::{state::Open, Card};
|
use openpgp_card_sequoia::{state::Open, Card};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct OpenPGPCard;
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
#[error("Provisioner was unable to find a matching smartcard")]
|
#[error("Provisioner was unable to find a matching smartcard")]
|
||||||
struct NoMatchingSmartcard;
|
struct NoMatchingSmartcard;
|
||||||
|
|
||||||
impl ProvisionExec for OpenPGPCard {
|
fn discover_cards() -> Result<Vec<(String, Option<String>)>, Box<dyn std::error::Error>> {
|
||||||
type PrivateKey = keyfork_derive_openpgp::XPrvKey;
|
|
||||||
|
|
||||||
fn discover(&self) -> Result<Vec<(String, Option<String>)>, Box<dyn std::error::Error>> {
|
|
||||||
let mut idents = vec![];
|
let mut idents = vec![];
|
||||||
for backend in PcscBackend::cards(None)? {
|
for backend in PcscBackend::cards(None)? {
|
||||||
let backend = backend?;
|
let backend = backend?;
|
||||||
|
@ -40,17 +34,12 @@ impl ProvisionExec for OpenPGPCard {
|
||||||
idents.push((identifier, name));
|
idents.push((identifier, name));
|
||||||
}
|
}
|
||||||
Ok(idents)
|
Ok(idents)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn derivation_prefix() -> keyfork_derive_util::DerivationPath {
|
fn provision_card(
|
||||||
keyfork_derive_path_data::paths::OPENPGP.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn provision(
|
|
||||||
&self,
|
|
||||||
xprv: XPrv,
|
|
||||||
provisioner: config::Provisioner,
|
provisioner: config::Provisioner,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
xprv: XPrv,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut pm = default_handler()?;
|
let mut pm = default_handler()?;
|
||||||
|
|
||||||
let (user_pin, admin_pin) = get_new_pins(&mut *pm)?;
|
let (user_pin, admin_pin) = get_new_pins(&mut *pm)?;
|
||||||
|
@ -115,5 +104,50 @@ impl ProvisionExec for OpenPGPCard {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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>;
|
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
|
fn derive_key(seed: [u8; 64], index: u8) -> Result<Cert> {
|
||||||
// recovery in the future.
|
|
||||||
fn derive_key(seed: [u8; 32], index: u8) -> Result<Cert> {
|
|
||||||
let subkeys = vec![
|
let subkeys = vec![
|
||||||
KeyFlags::empty().set_certification(),
|
KeyFlags::empty().set_certification(),
|
||||||
KeyFlags::empty().set_signing(),
|
KeyFlags::empty().set_signing(),
|
||||||
|
@ -167,7 +165,9 @@ fn cross_sign_certs(certs: &mut [Cert]) -> Result<(), Box<dyn std::error::Error>
|
||||||
|
|
||||||
impl GenerateShardSecret {
|
impl GenerateShardSecret {
|
||||||
fn handle(&self) -> Result<()> {
|
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 pm = default_handler()?;
|
||||||
let mut certs = vec![];
|
let mut certs = vec![];
|
||||||
let mut seen_cards: HashSet<String> = HashSet::new();
|
let mut seen_cards: HashSet<String> = HashSet::new();
|
||||||
|
@ -246,12 +246,18 @@ impl GenerateShardSecret {
|
||||||
|
|
||||||
if let Some(output_file) = self.output.as_ref() {
|
if let Some(output_file) = self.output.as_ref() {
|
||||||
let output = File::create(output_file)?;
|
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 {
|
} else {
|
||||||
opgp.shard_and_encrypt(
|
opgp.shard_and_encrypt(
|
||||||
self.threshold,
|
self.threshold,
|
||||||
certs.len() as u8,
|
certs.len() as u8,
|
||||||
&seed,
|
mnemonic.as_bytes(),
|
||||||
&certs[..],
|
&certs[..],
|
||||||
std::io::stdout(),
|
std::io::stdout(),
|
||||||
)?;
|
)?;
|
||||||
|
|
Loading…
Reference in New Issue