Implement --generate command

Includes logic to help users manage their keys:

- If the key is using a default PIN, we require the user to change it.
- We set the PUK equal to the PIN so the user doesn't need to remember
  them separately.
- We migrate the default management key to a new PIN-protected key.
This commit is contained in:
Jack Grigg
2021-01-03 19:47:10 +00:00
parent eedf9fa997
commit 850f96cd2c
7 changed files with 341 additions and 4 deletions
+53 -1
View File
@@ -1,10 +1,11 @@
//! Structs for handling YubiKeys.
use bech32::{ToBase32, Variant};
use dialoguer::Password;
use std::fmt;
use std::thread::sleep;
use std::time::{Duration, SystemTime};
use yubikey_piv::{key::RetiredSlotId, yubikey::Serial, Readers, YubiKey};
use yubikey_piv::{key::RetiredSlotId, yubikey::Serial, MgmKey, Readers, YubiKey};
use crate::{
error::Error,
@@ -69,6 +70,57 @@ pub(crate) fn open(serial: Option<Serial>) -> Result<YubiKey, Error> {
Ok(yubikey)
}
pub(crate) fn manage(yubikey: &mut YubiKey) -> Result<(), Error> {
eprintln!("");
let pin = Password::new()
.with_prompt(&format!(
"Enter PIN for YubiKey with serial {} (default is 123456)",
yubikey.serial(),
))
.interact()?;
yubikey.verify_pin(pin.as_bytes())?;
// If the user is using the default PIN, help them to change it.
if pin == "123456" {
eprintln!("");
eprintln!("✨ Your key is using the default PIN. Let's change it!");
eprintln!("✨ We'll also set the PUK equal to the PIN.");
eprintln!("");
eprintln!("🔐 The PIN is up to 8 numbers, letters, or symbols. Not just numbers!");
eprintln!(
"❌ Your keys will be lost if the PIN and PUK are locked after 3 incorrect tries."
);
eprintln!("");
let current_puk = Password::new()
.with_prompt("Enter current PUK (default is 12345678)")
.interact()?;
let new_pin = Password::new()
.with_prompt("Choose a new PIN/PUK")
.with_confirmation("Repeat the PIN/PUK", "PINs don't match")
.interact()?;
if new_pin.len() > 8 {
return Err(Error::InvalidPinLength);
}
yubikey.change_puk(current_puk.as_bytes(), new_pin.as_bytes())?;
yubikey.change_pin(pin.as_bytes(), new_pin.as_bytes())?;
}
if let Ok(mgm_key) = MgmKey::get_protected(yubikey) {
yubikey.authenticate(mgm_key)?;
} else {
// Try to authenticate with the default management key.
yubikey
.authenticate(MgmKey::default())
.map_err(|_| Error::CustomManagementKey)?;
// Migrate to a PIN-protected management key.
let mgm_key = MgmKey::generate()?;
mgm_key.set_protected(yubikey)?;
}
Ok(())
}
/// A reference to an age key stored in a YubiKey.
#[derive(Debug)]
pub struct Stub {