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:
+53
-1
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user