Clean up some of the management key code (#584)

* mgm: Move TDES weak key checking code into a submodule
* piv: Extract management key algorithm into a separate enum
* mgm: Check management key algorithm when fetching from Yubikey
This commit is contained in:
Jack Grigg
2025-02-11 19:19:53 +00:00
committed by GitHub
parent 19e1cccfec
commit 235eb6215e
7 changed files with 189 additions and 102 deletions
+21 -30
View File
@@ -45,8 +45,8 @@
use crate::{
apdu::{Ins, StatusWords},
certificate::{self, Certificate},
consts::CB_OBJ_MAX,
error::{Error, Result},
mgm::MgmAlgorithmId,
policy::{PinPolicy, TouchPolicy},
serialization::*,
setting,
@@ -74,6 +74,9 @@ use {
#[cfg(feature = "untested")]
use zeroize::Zeroizing;
#[cfg(feature = "untested")]
use crate::consts::CB_OBJ_MAX;
/// PIV Applet Name
pub(crate) const APPLET_NAME: &str = "PIV";
@@ -924,28 +927,15 @@ pub fn decrypt_data(
/// Read metadata
pub fn metadata(yubikey: &mut YubiKey, slot: SlotId) -> Result<SlotMetadata> {
let txn = yubikey.begin_transaction()?;
let templ = [0, Ins::GetMetadata.code(), 0, slot.into()];
let response = txn.transfer_data(&templ, &[], CB_OBJ_MAX)?;
if !response.is_success() {
if response.status_words() == StatusWords::NotSupportedError {
return Err(Error::NotSupported); // Requires firmware 5.2.3
} else {
return Err(Error::GenericError);
}
}
let buf = Buffer::new(response.data().into());
SlotMetadata::try_from(buf)
txn.get_metadata(slot)
}
/// Metadata from a slot
#[derive(Debug)]
pub struct SlotMetadata {
/// Algorithm / Type of key
pub algorithm: ManagementAlgorithmId,
pub algorithm: SlotAlgorithmId,
/// PIN and touch policy
pub policy: Option<(PinPolicy, TouchPolicy)>,
/// Imported or generated key
@@ -972,7 +962,7 @@ impl TryFrom<Buffer> for SlotMetadata {
|input| Tlv::parse(input).map_err(|_| nom::Err::Error(())),
|| {
Ok(SlotMetadata {
algorithm: ManagementAlgorithmId::PinPuk,
algorithm: SlotAlgorithmId::PinPuk,
policy: None,
origin: None,
public: None,
@@ -983,7 +973,7 @@ impl TryFrom<Buffer> for SlotMetadata {
|acc: Result<SlotMetadata>, tlv| match acc {
Ok(mut metadata) => match tlv.tag {
1 => {
metadata.algorithm = ManagementAlgorithmId::try_from(tlv.value[0])?;
metadata.algorithm = SlotAlgorithmId::try_from(tlv.value[0])?;
Ok(metadata)
}
2 => {
@@ -1015,7 +1005,7 @@ impl TryFrom<Buffer> for SlotMetadata {
}
4 => {
match metadata.algorithm {
ManagementAlgorithmId::Asymmetric(alg) => {
SlotAlgorithmId::Asymmetric(alg) => {
metadata.public = Some(read_public_key(alg, tlv.value, false)?);
}
_ => Err(Error::ParseError)?,
@@ -1215,33 +1205,34 @@ fn read_public_key(
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
/// Algorithms as reported by the metadata command.
pub enum ManagementAlgorithmId {
pub enum SlotAlgorithmId {
/// Used on PIN and PUK slots.
PinPuk,
/// Used on the key management slot.
ThreeDes,
Management(MgmAlgorithmId),
/// Used on all other slots.
Asymmetric(AlgorithmId),
}
impl TryFrom<u8> for ManagementAlgorithmId {
impl TryFrom<u8> for SlotAlgorithmId {
type Error = Error;
fn try_from(value: u8) -> Result<Self> {
match value {
0xff => Ok(ManagementAlgorithmId::PinPuk),
0x03 => Ok(ManagementAlgorithmId::ThreeDes),
oth => AlgorithmId::try_from(oth).map(ManagementAlgorithmId::Asymmetric),
0xff => Ok(SlotAlgorithmId::PinPuk),
oth => MgmAlgorithmId::try_from(oth)
.map(SlotAlgorithmId::Management)
.or_else(|_| AlgorithmId::try_from(oth).map(SlotAlgorithmId::Asymmetric)),
}
}
}
impl From<ManagementAlgorithmId> for u8 {
fn from(id: ManagementAlgorithmId) -> u8 {
impl From<SlotAlgorithmId> for u8 {
fn from(id: SlotAlgorithmId) -> u8 {
match id {
ManagementAlgorithmId::PinPuk => 0xff,
ManagementAlgorithmId::ThreeDes => 0x03,
ManagementAlgorithmId::Asymmetric(oth) => oth.into(),
SlotAlgorithmId::PinPuk => 0xff,
SlotAlgorithmId::Management(oth) => oth.into(),
SlotAlgorithmId::Asymmetric(oth) => oth.into(),
}
}
}