keyfork: improve prompt UX of `wizard generate-shard-secret`
This commit is contained in:
parent
240a10a063
commit
4c6c071539
|
@ -1,6 +1,6 @@
|
|||
use super::Keyfork;
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::{collections::HashSet, io::IsTerminal, path::PathBuf, fs::OpenOptions};
|
||||
use std::{collections::HashSet, fs::OpenOptions, io::IsTerminal, path::PathBuf};
|
||||
|
||||
use card_backend_pcsc::PcscBackend;
|
||||
use openpgp_card_sequoia::{state::Open, types::KeyType, Card};
|
||||
|
@ -56,6 +56,7 @@ fn factory_reset_current_card(
|
|||
user_pin: &str,
|
||||
admin_pin: &str,
|
||||
cert: &Cert,
|
||||
card_backend: PcscBackend,
|
||||
) -> Result<()> {
|
||||
let policy = openpgp::policy::NullPolicy::new();
|
||||
let valid_cert = cert.with_policy(&policy, None)?;
|
||||
|
@ -77,30 +78,31 @@ fn factory_reset_current_card(
|
|||
.secret()
|
||||
.next()
|
||||
.expect("no authentication key found");
|
||||
if let Some(current_backend) = PcscBackend::cards(None)?.next().transpose()? {
|
||||
let mut card = Card::<Open>::new(current_backend)?;
|
||||
let mut transaction = card.transaction()?;
|
||||
let application_identifier = transaction.application_identifier()?.ident();
|
||||
if seen_cards.contains(&application_identifier) {
|
||||
// we were given the same card, error
|
||||
panic!("Previously used card {application_identifier} was reused");
|
||||
} else {
|
||||
seen_cards.insert(application_identifier);
|
||||
}
|
||||
transaction.factory_reset()?;
|
||||
let mut admin = transaction.to_admin_card("12345678")?;
|
||||
admin.upload_key(signing_key, KeyType::Signing, None)?;
|
||||
admin.upload_key(decryption_key, KeyType::Decryption, None)?;
|
||||
admin.upload_key(authentication_key, KeyType::Authentication, None)?;
|
||||
transaction.change_user_pin("123456", user_pin)?;
|
||||
transaction.change_admin_pin("12345678", admin_pin)?;
|
||||
let mut card = Card::<Open>::new(card_backend)?;
|
||||
let mut transaction = card.transaction()?;
|
||||
let application_identifier = transaction.application_identifier()?.ident();
|
||||
if seen_cards.contains(&application_identifier) {
|
||||
// we were given the same card, error
|
||||
panic!("Previously used card {application_identifier} was reused");
|
||||
} else {
|
||||
panic!("No smart card found");
|
||||
seen_cards.insert(application_identifier);
|
||||
}
|
||||
transaction.factory_reset()?;
|
||||
let mut admin = transaction.to_admin_card("12345678")?;
|
||||
admin.upload_key(signing_key, KeyType::Signing, None)?;
|
||||
admin.upload_key(decryption_key, KeyType::Decryption, None)?;
|
||||
admin.upload_key(authentication_key, KeyType::Authentication, None)?;
|
||||
transaction.change_user_pin("123456", user_pin)?;
|
||||
transaction.change_admin_pin("12345678", admin_pin)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_shard_secret(threshold: u8, max: u8, keys_per_shard: u8, output_file: &Option<PathBuf>) -> Result<()> {
|
||||
fn generate_shard_secret(
|
||||
threshold: u8,
|
||||
max: u8,
|
||||
keys_per_shard: u8,
|
||||
output_file: &Option<PathBuf>,
|
||||
) -> Result<()> {
|
||||
let seed = keyfork_entropy::generate_entropy_of_size(256 / 8)?;
|
||||
let mut pm = Terminal::new(std::io::stdin(), std::io::stderr())?;
|
||||
let mut certs = vec![];
|
||||
|
@ -128,10 +130,19 @@ fn generate_shard_secret(threshold: u8, max: u8, keys_per_shard: u8, output_file
|
|||
let cert = derive_key(&seed, index)?;
|
||||
for i in 0..keys_per_shard {
|
||||
pm.prompt_message(Message::Text(format!(
|
||||
"Please insert key #{} for user #{}",
|
||||
"Please remove all keys and insert key #{} for user #{}",
|
||||
i + 1,
|
||||
index + 1,
|
||||
)))?;
|
||||
let card_backend = loop {
|
||||
if let Some(c) = PcscBackend::cards(None)?.next().transpose()? {
|
||||
break c;
|
||||
}
|
||||
pm.prompt_message(Message::Text(
|
||||
"No smart card was found. Please plug in a smart card and press enter"
|
||||
.to_string(),
|
||||
))?;
|
||||
};
|
||||
let user_pin = pm.prompt_validated_passphrase(
|
||||
"Please enter the new smartcard User PIN: ",
|
||||
3,
|
||||
|
@ -142,7 +153,13 @@ fn generate_shard_secret(threshold: u8, max: u8, keys_per_shard: u8, output_file
|
|||
3,
|
||||
&admin_pin_validator,
|
||||
)?;
|
||||
factory_reset_current_card(&mut seen_cards, user_pin.trim(), admin_pin.trim(), &cert)?;
|
||||
factory_reset_current_card(
|
||||
&mut seen_cards,
|
||||
user_pin.trim(),
|
||||
admin_pin.trim(),
|
||||
&cert,
|
||||
card_backend,
|
||||
)?;
|
||||
}
|
||||
certs.push(cert);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ pub enum Error {
|
|||
#[error("Validation of the input failed after {0} retries (last error: {1})")]
|
||||
Validation(u8, String),
|
||||
|
||||
/// A ctrl-c interrupt was caught by the handler.
|
||||
#[error("User pressed ctrl-c, terminating the session")]
|
||||
CtrlC,
|
||||
|
||||
/// An error occurred while interacting with a terminal.
|
||||
#[error("IO Error: {0}")]
|
||||
IO(#[from] std::io::Error),
|
||||
|
|
|
@ -269,6 +269,9 @@ impl<R, W> PromptHandler for Terminal<R, W> where R: Read + Sized, W: Write + As
|
|||
input.push(' ');
|
||||
}
|
||||
}
|
||||
KeyCode::Char('c') if k.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||
return Err(Error::CtrlC);
|
||||
}
|
||||
KeyCode::Char(' ') => {
|
||||
if !input.chars().next_back().is_some_and(char::is_whitespace) {
|
||||
input.push(' ');
|
||||
|
@ -410,6 +413,9 @@ impl<R, W> PromptHandler for Terminal<R, W> where R: Read + Sized, W: Write + As
|
|||
.flush()?;
|
||||
}
|
||||
}
|
||||
KeyCode::Char('c') if k.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||
return Err(Error::CtrlC);
|
||||
}
|
||||
KeyCode::Char(c) => {
|
||||
if prefix_length + passphrase.len() < (cols - 1) as usize {
|
||||
terminal.queue(Print("*"))?.flush()?;
|
||||
|
@ -485,6 +491,9 @@ impl<R, W> PromptHandler for Terminal<R, W> where R: Read + Sized, W: Write + As
|
|||
#[allow(clippy::single_match)]
|
||||
match read()? {
|
||||
Event::Key(k) => match k.code {
|
||||
KeyCode::Char('c') if k.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||
return Err(Error::CtrlC);
|
||||
}
|
||||
KeyCode::Enter | KeyCode::Char(' ' | 'q') => break,
|
||||
_ => (),
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue