Request PIN before certificate generation if PIN policy is "always"

We also correctly ask for a PIN touch after the key is generated (which
does not need it) but before certificate generation (which does if the
touch policy is not "none").

Closes str4d/age-plugin-yubikey#101.
This commit is contained in:
Jack Grigg
2023-01-03 02:09:57 +00:00
parent e26ed3a163
commit 45f6580be4
3 changed files with 34 additions and 6 deletions
+4
View File
@@ -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`
+6
View File
@@ -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
+24 -6
View File
@@ -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),