Add --list comments to identity output
This improves the output of --generate and --identity, as well as the interactive TUI. Closes str4d/age-plugin-yubikey#24.
This commit is contained in:
+4
-4
@@ -10,7 +10,7 @@ use yubikey_piv::{
|
||||
use crate::{
|
||||
error::Error,
|
||||
p256::Recipient,
|
||||
util::POLICY_EXTENSION_OID,
|
||||
util::{Metadata, POLICY_EXTENSION_OID},
|
||||
yubikey::{self, Stub},
|
||||
BINARY_NAME, USABLE_SLOTS,
|
||||
};
|
||||
@@ -57,7 +57,7 @@ impl IdentityBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn build(self, yubikey: &mut YubiKey) -> Result<(Stub, Recipient, String), Error> {
|
||||
pub(crate) fn build(self, yubikey: &mut YubiKey) -> Result<(Stub, Recipient, Metadata), Error> {
|
||||
let slot = match self.slot {
|
||||
Some(slot) => {
|
||||
if !self.force {
|
||||
@@ -141,12 +141,12 @@ impl IdentityBuilder {
|
||||
)?;
|
||||
|
||||
let (_, cert) = x509_parser::parse_x509_certificate(cert.as_ref()).unwrap();
|
||||
let created = cert.validity().not_before.to_rfc2822();
|
||||
let metadata = Metadata::extract(yubikey, slot, &cert, false).unwrap();
|
||||
|
||||
Ok((
|
||||
Stub::new(yubikey.serial(), slot, &recipient),
|
||||
recipient,
|
||||
created,
|
||||
metadata,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
+15
-28
@@ -119,14 +119,14 @@ fn generate(opts: PluginOptions) -> Result<(), Error> {
|
||||
|
||||
let mut yubikey = yubikey::open(serial)?;
|
||||
|
||||
let (stub, recipient, created) = builder::IdentityBuilder::new(slot)
|
||||
let (stub, recipient, metadata) = builder::IdentityBuilder::new(slot)
|
||||
.with_name(opts.name)
|
||||
.with_pin_policy(pin_policy)
|
||||
.with_touch_policy(touch_policy)
|
||||
.force(opts.force)
|
||||
.build(&mut yubikey)?;
|
||||
|
||||
util::print_identity(stub, recipient, &created);
|
||||
util::print_identity(stub, recipient, metadata);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -173,12 +173,12 @@ fn identity(opts: PluginOptions) -> Result<(), Error> {
|
||||
}?;
|
||||
|
||||
let stub = yubikey::Stub::new(yubikey.serial(), slot, &recipient);
|
||||
let created = x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||
let metadata = x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||
.ok()
|
||||
.map(|(_, cert)| cert.validity().not_before.to_rfc2822())
|
||||
.unwrap_or_else(|| "Unknown".to_owned());
|
||||
.and_then(|(_, cert)| util::Metadata::extract(&mut yubikey, slot, &cert, true))
|
||||
.unwrap();
|
||||
|
||||
util::print_identity(stub, recipient, &created);
|
||||
util::print_identity(stub, recipient, metadata);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -205,29 +205,15 @@ fn list(all: bool) -> Result<(), Error> {
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let ((name, pin_policy, touch_policy), created) =
|
||||
match x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||
let metadata = match x509_parser::parse_x509_certificate(key.certificate().as_ref())
|
||||
.ok()
|
||||
.and_then(|(_, cert)| {
|
||||
util::extract_name_and_policies(&mut yubikey, &key, &cert, all)
|
||||
.map(|res| (res, cert.validity().not_before.to_rfc2822()))
|
||||
}) {
|
||||
.and_then(|(_, cert)| util::Metadata::extract(&mut yubikey, slot, &cert, all))
|
||||
{
|
||||
Some(res) => res,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
println!(
|
||||
"# Serial: {}, Slot: {}",
|
||||
yubikey.serial(),
|
||||
util::slot_to_ui(&slot),
|
||||
);
|
||||
println!("# Name: {}", name);
|
||||
println!("# Created: {}", created);
|
||||
println!("# PIN policy: {}", util::pin_policy_to_str(pin_policy));
|
||||
println!(
|
||||
"# Touch policy: {}",
|
||||
util::touch_policy_to_str(touch_policy)
|
||||
);
|
||||
println!("{}", metadata);
|
||||
println!("{}", recipient.to_string());
|
||||
println!();
|
||||
}
|
||||
@@ -358,7 +344,7 @@ fn main() -> Result<(), Error> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let (stub, recipient, created) = {
|
||||
let (stub, recipient, metadata) = {
|
||||
let (slot_index, slot) = loop {
|
||||
match Select::new()
|
||||
.with_prompt("🕳️ Select a slot for your age identity")
|
||||
@@ -391,9 +377,10 @@ fn main() -> Result<(), Error> {
|
||||
let stub = yubikey::Stub::new(yubikey.serial(), slot, &recipient);
|
||||
let (_, cert) =
|
||||
x509_parser::parse_x509_certificate(key.certificate().as_ref()).unwrap();
|
||||
let created = cert.validity().not_before.to_rfc2822();
|
||||
let metadata =
|
||||
util::Metadata::extract(&mut yubikey, slot, &cert, true).unwrap();
|
||||
|
||||
(stub, recipient, created)
|
||||
(stub, recipient, metadata)
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -449,7 +436,7 @@ fn main() -> Result<(), Error> {
|
||||
}
|
||||
};
|
||||
|
||||
util::print_identity(stub, recipient, &created);
|
||||
util::print_identity(stub, recipient, metadata);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+52
-10
@@ -1,8 +1,10 @@
|
||||
use std::fmt;
|
||||
|
||||
use x509_parser::{certificate::X509Certificate, der_parser::oid::Oid};
|
||||
use yubikey_piv::{
|
||||
key::RetiredSlotId,
|
||||
key::{RetiredSlotId, SlotId},
|
||||
policy::{PinPolicy, TouchPolicy},
|
||||
Key, YubiKey,
|
||||
Serial, YubiKey,
|
||||
};
|
||||
|
||||
use crate::{error::Error, p256::Recipient, yubikey::Stub, BINARY_NAME, USABLE_SLOTS};
|
||||
@@ -89,12 +91,22 @@ pub(crate) fn extract_name(cert: &X509Certificate, all: bool) -> Option<(String,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn extract_name_and_policies(
|
||||
pub(crate) struct Metadata {
|
||||
serial: Serial,
|
||||
slot: RetiredSlotId,
|
||||
name: String,
|
||||
created: String,
|
||||
pin_policy: Option<PinPolicy>,
|
||||
touch_policy: Option<TouchPolicy>,
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub(crate) fn extract(
|
||||
yubikey: &mut YubiKey,
|
||||
key: &Key,
|
||||
slot: RetiredSlotId,
|
||||
cert: &X509Certificate,
|
||||
all: bool,
|
||||
) -> Option<(String, Option<PinPolicy>, Option<TouchPolicy>)> {
|
||||
) -> Option<Self> {
|
||||
// We store the PIN and touch policies for identities in their certificates
|
||||
// using the same certificate extension as PIV attestations.
|
||||
// https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
|
||||
@@ -123,14 +135,16 @@ pub(crate) fn extract_name_and_policies(
|
||||
.unwrap_or((None, None))
|
||||
};
|
||||
|
||||
extract_name(cert, all).map(|(name, ours)| {
|
||||
extract_name(cert, all)
|
||||
.map(|(name, ours)| {
|
||||
if ours {
|
||||
let (pin_policy, touch_policy) = policies(&cert);
|
||||
(name, pin_policy, touch_policy)
|
||||
} else {
|
||||
// We can extract the PIN and touch policies via an attestation. This
|
||||
// is slow, but the user has asked for all compatible keys, so...
|
||||
let (pin_policy, touch_policy) = yubikey_piv::key::attest(yubikey, key.slot())
|
||||
let (pin_policy, touch_policy) =
|
||||
yubikey_piv::key::attest(yubikey, SlotId::Retired(slot))
|
||||
.ok()
|
||||
.and_then(|buf| {
|
||||
x509_parser::parse_x509_certificate(&buf)
|
||||
@@ -142,15 +156,43 @@ pub(crate) fn extract_name_and_policies(
|
||||
(name, pin_policy, touch_policy)
|
||||
}
|
||||
})
|
||||
.map(|(name, pin_policy, touch_policy)| Metadata {
|
||||
serial: yubikey.serial(),
|
||||
slot,
|
||||
name,
|
||||
created: cert.validity().not_before.to_rfc2822(),
|
||||
pin_policy,
|
||||
touch_policy,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_identity(stub: Stub, recipient: Recipient, created: &str) {
|
||||
impl fmt::Display for Metadata {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
"# Serial: {}, Slot: {}",
|
||||
self.serial,
|
||||
slot_to_ui(&self.slot)
|
||||
)?;
|
||||
writeln!(f, "# Name: {}", self.name)?;
|
||||
writeln!(f, "# Created: {}", self.created)?;
|
||||
writeln!(f, "# PIN policy: {}", pin_policy_to_str(self.pin_policy))?;
|
||||
write!(
|
||||
f,
|
||||
"# Touch policy: {}",
|
||||
touch_policy_to_str(self.touch_policy)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_identity(stub: Stub, recipient: Recipient, metadata: Metadata) {
|
||||
let recipient = recipient.to_string();
|
||||
if !console::user_attended() {
|
||||
eprintln!("Recipient: {}", recipient);
|
||||
}
|
||||
|
||||
println!("# created: {}", created);
|
||||
println!("# recipient: {}", recipient);
|
||||
println!("{}", metadata);
|
||||
println!("# Recipient: {}", recipient);
|
||||
println!("{}", stub.to_string());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user