From b07600673c89c873968adf99c84fd22c27cf97bc Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Wed, 15 Jul 2026 12:26:03 -0400 Subject: [PATCH 1/3] PIV unlock should fetch management key alg instead of using firmware default --- src/yubikey/piv/management.rs | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/yubikey/piv/management.rs b/src/yubikey/piv/management.rs index 3bc6ca5..7b682ed 100644 --- a/src/yubikey/piv/management.rs +++ b/src/yubikey/piv/management.rs @@ -3,7 +3,9 @@ use crate::{PublicKey, TouchRequirement}; use ring::digest; use yubikey::certificate::Certificate; -use yubikey::piv::{attest, sign_data as yk_sign_data, AlgorithmId, SlotId}; +use yubikey::piv::{ + attest, sign_data as yk_sign_data, AlgorithmId, ManagementSlotId, SlotAlgorithmId, SlotId, +}; use yubikey::{MgmAlgorithmId, MgmKey, Serial, YubiKey}; use yubikey::{PinPolicy, TouchPolicy}; @@ -209,11 +211,28 @@ impl super::Yubikey { Ok(()) } - fn management_key_from_bytes(&self, mgm_key: &[u8]) -> Result { - let alg = MgmKey::get_default(&self.yk)?.algorithm_id(); + fn management_key_from_bytes(&mut self, mgm_key: &[u8]) -> Result { + // Authenticate with the algorithm the management key is actually + // configured with, read from the card. Fall back to the firmware + // default for devices that don't expose management-key metadata (those + // only support 3DES, which the default already resolves to). + let alg = match self.management_key_algorithm() { + Some(alg) => alg, + None => MgmKey::get_default(&self.yk)?.algorithm_id(), + }; MgmKey::from_bytes(mgm_key, Some(alg)).map_err(|_| Error::InvalidManagementKey) } + /// The algorithm the management key is currently set to, if the device + /// exposes it via metadata. + fn management_key_algorithm(&mut self) -> Option { + let slot = SlotId::Management(ManagementSlotId::Management); + match yubikey::piv::metadata(&mut self.yk, slot).map(|m| m.algorithm) { + Ok(SlotAlgorithmId::Management(alg)) => Some(alg), + _ => None, + } + } + /// Fetch the serial number of the Yubikey pub fn serial(&mut self) -> Result { let serial = self.yk.serial(); From e5a169f34a108658d7e7aaa75b29e10583fc8c31 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Tue, 28 Jul 2026 12:04:45 -0400 Subject: [PATCH 2/3] Handle unsupported metadata --- src/yubikey/piv/management.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/yubikey/piv/management.rs b/src/yubikey/piv/management.rs index 7b682ed..930a217 100644 --- a/src/yubikey/piv/management.rs +++ b/src/yubikey/piv/management.rs @@ -216,7 +216,7 @@ impl super::Yubikey { // configured with, read from the card. Fall back to the firmware // default for devices that don't expose management-key metadata (those // only support 3DES, which the default already resolves to). - let alg = match self.management_key_algorithm() { + let alg = match self.management_key_algorithm()? { Some(alg) => alg, None => MgmKey::get_default(&self.yk)?.algorithm_id(), }; @@ -225,11 +225,13 @@ impl super::Yubikey { /// The algorithm the management key is currently set to, if the device /// exposes it via metadata. - fn management_key_algorithm(&mut self) -> Option { + fn management_key_algorithm(&mut self) -> Result> { let slot = SlotId::Management(ManagementSlotId::Management); match yubikey::piv::metadata(&mut self.yk, slot).map(|m| m.algorithm) { - Ok(SlotAlgorithmId::Management(alg)) => Some(alg), - _ => None, + Ok(SlotAlgorithmId::Management(alg)) => Ok(Some(alg)), + Ok(_) => Ok(None), + Err(yubikey::Error::NotSupported) => Ok(None), + Err(e) => Err(e.into()), } } From def2f7459634c3247c400773b0243c31727afb84 Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Date: Thu, 30 Jul 2026 19:37:12 -0400 Subject: [PATCH 3/3] Comment --- src/yubikey/piv/management.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/yubikey/piv/management.rs b/src/yubikey/piv/management.rs index 930a217..800820a 100644 --- a/src/yubikey/piv/management.rs +++ b/src/yubikey/piv/management.rs @@ -212,10 +212,8 @@ impl super::Yubikey { } fn management_key_from_bytes(&mut self, mgm_key: &[u8]) -> Result { - // Authenticate with the algorithm the management key is actually - // configured with, read from the card. Fall back to the firmware - // default for devices that don't expose management-key metadata (those - // only support 3DES, which the default already resolves to). + // Use the configured algorithm when metadata is available. Older + // devices fall back to their default algorithm. let alg = match self.management_key_algorithm()? { Some(alg) => alg, None => MgmKey::get_default(&self.yk)?.algorithm_id(),