diff --git a/CHANGELOG.md b/CHANGELOG.md index ba9c8cf..5b13f6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ to 0.3.0 are beta releases. `age-plugin-yubikey` won't request a PIN entry to decrypt a file with an identity that has a PIN policy of `once`. +### Fixed +- Identities can now be generated with a PIN policy of "always" (in previous + versions of `age-plugin-yubikey` this would cause an error). + ## [0.3.2] - 2023-01-01 ### Changed - The "sharing violation" logic now also sends SIGHUP to any `yubikey-agent` diff --git a/i18n/en-US/age_plugin_yubikey.ftl b/i18n/en-US/age_plugin_yubikey.ftl index d3403be..9beb5d8 100644 --- a/i18n/en-US/age_plugin_yubikey.ftl +++ b/i18n/en-US/age_plugin_yubikey.ftl @@ -144,6 +144,12 @@ mgr-changing-mgmt-key-error = {" "}{$management_key} mgr-changing-mgmt-key-success = Success! +## YubiKey keygen + +builder-gen-key = 🎲 Generating key... +builder-gen-cert = 🔏 Generating certificate... +builder-touch-yk = 👆 Please touch the {-yubikey} + ## Plugin usage plugin-err-invalid-recipient = Invalid recipient diff --git a/src/builder.rs b/src/builder.rs index 72c91d7..653789e 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,3 +1,4 @@ +use dialoguer::Password; use rand::{rngs::OsRng, RngCore}; use x509::RelativeDistinguishedName; use yubikey::{ @@ -8,6 +9,7 @@ use yubikey::{ use crate::{ error::Error, + fl, key::{self, Stub}, p256::Recipient, util::{Metadata, POLICY_EXTENSION_OID}, @@ -86,17 +88,13 @@ impl IdentityBuilder { let pin_policy = self.pin_policy.unwrap_or(DEFAULT_PIN_POLICY); let touch_policy = self.touch_policy.unwrap_or(DEFAULT_TOUCH_POLICY); + eprintln!("{}", fl!("builder-gen-key")); + // No need to ask for users to enter their PIN if the PIN policy requires it, // because here we _always_ require them to enter their PIN in order to access the // protected management key (which is necessary in order to generate identities). key::manage(yubikey)?; - if let TouchPolicy::Never = touch_policy { - // No need to touch YubiKey - } else { - eprintln!("👆 Please touch the YubiKey"); - } - // Generate a new key in the selected slot. let generated = yubikey_generate( yubikey, @@ -109,6 +107,9 @@ impl IdentityBuilder { let recipient = Recipient::from_spki(&generated).expect("YubiKey generates a valid pubkey"); let stub = Stub::new(yubikey.serial(), slot, &recipient); + eprintln!(); + eprintln!("{}", fl!("builder-gen-cert")); + // Pick a random serial for the new self-signed certificate. let mut serial = [0; 20]; OsRng.fill_bytes(&mut serial); @@ -117,6 +118,23 @@ impl IdentityBuilder { .name .unwrap_or(format!("age identity {}", hex::encode(stub.tag))); + if let PinPolicy::Always = pin_policy { + // We need to enter the PIN again. + let pin = Password::new() + .with_prompt(fl!( + "plugin-enter-pin", + yubikey_serial = yubikey.serial().to_string(), + )) + .report(true) + .interact()?; + yubikey.verify_pin(pin.as_bytes())?; + } + if let TouchPolicy::Never = touch_policy { + // No need to touch YubiKey + } else { + eprintln!("{}", fl!("builder-touch-yk")); + } + let cert = Certificate::generate_self_signed( yubikey, SlotId::Retired(slot),