diff --git a/src/builder.rs b/src/builder.rs index aa694e2..f01f131 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -1,7 +1,7 @@ use rand::{rngs::OsRng, RngCore}; use x509::RelativeDistinguishedName; use yubikey::{ - certificate::{Certificate, PublicKeyInfo}, + certificate::Certificate, piv::{generate as yubikey_generate, AlgorithmId, RetiredSlotId, SlotId}, Key, PinPolicy, TouchPolicy, YubiKey, }; @@ -106,12 +106,7 @@ impl IdentityBuilder { touch_policy, )?; - let recipient = match &generated { - PublicKeyInfo::EcP256(pubkey) => { - Recipient::from_encoded(pubkey).expect("YubiKey generates a valid pubkey") - } - _ => unreachable!(), - }; + let recipient = Recipient::from_spki(&generated).expect("YubiKey generates a valid pubkey"); let stub = Stub::new(yubikey.serial(), slot, &recipient); // Pick a random serial for the new self-signed certificate. diff --git a/src/key.rs b/src/key.rs index aa7bab6..78bcba1 100644 --- a/src/key.rs +++ b/src/key.rs @@ -15,7 +15,7 @@ use std::iter; use std::thread::sleep; use std::time::{Duration, Instant, SystemTime}; use yubikey::{ - certificate::{Certificate, PublicKeyInfo}, + certificate::Certificate, piv::{decrypt_data, AlgorithmId, RetiredSlotId, SlotId}, reader::{Context, Reader}, MgmKey, PinPolicy, Serial, TouchPolicy, YubiKey, @@ -459,11 +459,10 @@ impl Stub { // Read the pubkey from the YubiKey slot and check it still matches. let (cert, pk) = match Certificate::read(&mut yubikey, SlotId::Retired(self.slot)) .ok() - .and_then(|cert| match cert.subject_pki() { - PublicKeyInfo::EcP256(pubkey) => Recipient::from_encoded(pubkey) + .and_then(|cert| { + Recipient::from_certificate(&cert) .filter(|pk| pk.tag() == self.tag) - .map(|pk| (cert, pk)), - _ => None, + .map(|pk| (cert, pk)) }) { Some(pk) => pk, None => { diff --git a/src/main.rs b/src/main.rs index 9a0d03c..a806a60 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,6 @@ use i18n_embed::{ use lazy_static::lazy_static; use rust_embed::RustEmbed; use yubikey::{ - certificate::PublicKeyInfo, piv::{RetiredSlotId, SlotId}, reader::Context, Key, PinPolicy, Serial, TouchPolicy, @@ -196,9 +195,9 @@ fn print_single( let mut keys = Key::list(&mut yubikey)?.into_iter().filter_map(|key| { // - We only use the retired slots. // - Only P-256 keys are compatible with us. - match (key.slot(), key.certificate().subject_pki()) { - (SlotId::Retired(slot), PublicKeyInfo::EcP256(pubkey)) => { - p256::Recipient::from_encoded(pubkey).map(|r| (key, slot, r)) + match key.slot() { + SlotId::Retired(slot) => { + p256::Recipient::from_certificate(key.certificate()).map(|r| (key, slot, r)) } _ => None, } @@ -244,12 +243,9 @@ fn print_multiple( }; // Only P-256 keys are compatible with us. - let recipient = match key.certificate().subject_pki() { - PublicKeyInfo::EcP256(pubkey) => match p256::Recipient::from_encoded(pubkey) { - Some(recipient) => recipient, - None => continue, - }, - _ => continue, + let recipient = match p256::Recipient::from_certificate(key.certificate()) { + Some(recipient) => recipient, + None => continue, }; let stub = key::Stub::new(yubikey.serial(), slot, &recipient); @@ -429,20 +425,17 @@ fn main() -> Result<(), Error> { .map(|&slot| { keys.iter() .find(|key| key.slot() == SlotId::Retired(slot)) - .map(|key| match key.certificate().subject_pki() { - PublicKeyInfo::EcP256(pubkey) => { - p256::Recipient::from_encoded(pubkey).map(|_| { - // Cache the details we need to display to the user. - let (_, cert) = - x509_parser::parse_x509_certificate(key.certificate().as_ref()) - .unwrap(); - let (name, _) = util::extract_name(&cert, true).unwrap(); - let created = cert.validity().not_before.to_rfc2822(); + .map(|key| { + p256::Recipient::from_certificate(key.certificate()).map(|_| { + // Cache the details we need to display to the user. + let (_, cert) = + x509_parser::parse_x509_certificate(key.certificate().as_ref()) + .unwrap(); + let (name, _) = util::extract_name(&cert, true).unwrap(); + let created = cert.validity().not_before.to_rfc2822(); - format!("{}, created: {}", name, created) - }) - } - _ => None, + format!("{}, created: {}", name, created) + }) }) }) .collect(); @@ -492,12 +485,8 @@ fn main() -> Result<(), Error> { }; if let Some(key) = keys.iter().find(|key| key.slot() == SlotId::Retired(slot)) { - let recipient = match key.certificate().subject_pki() { - PublicKeyInfo::EcP256(pubkey) => { - p256::Recipient::from_encoded(pubkey).expect("We checked this above") - } - _ => unreachable!(), - }; + let recipient = p256::Recipient::from_certificate(key.certificate()) + .expect("We checked this above"); if Confirm::new() .with_prompt(i18n_embed_fl::fl!( diff --git a/src/p256.rs b/src/p256.rs index a85bb47..1eeecad 100644 --- a/src/p256.rs +++ b/src/p256.rs @@ -1,6 +1,8 @@ use bech32::{ToBase32, Variant}; use p256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint}; use sha2::{Digest, Sha256}; +use yubikey::{certificate::PublicKeyInfo, Certificate}; + use std::fmt; use crate::RECIPIENT_PREFIX; @@ -42,11 +44,22 @@ impl Recipient { } } + pub(crate) fn from_certificate(cert: &Certificate) -> Option { + Self::from_spki(cert.subject_pki()) + } + + pub(crate) fn from_spki(spki: &PublicKeyInfo) -> Option { + match spki { + PublicKeyInfo::EcP256(pubkey) => Self::from_encoded(pubkey), + _ => None, + } + } + /// Attempts to parse a valid YubiKey recipient from its SEC-1 encoding. /// /// This accepts both compressed (as used by the plugin) and uncompressed (as used in /// the YubiKey certificate) encodings. - pub(crate) fn from_encoded(encoded: &p256::EncodedPoint) -> Option { + fn from_encoded(encoded: &p256::EncodedPoint) -> Option { p256::PublicKey::from_encoded_point(encoded).map(Recipient) }