diff --git a/src/certificate.rs b/src/certificate.rs index 71a3db4e..6dbf4a58 100644 --- a/src/certificate.rs +++ b/src/certificate.rs @@ -31,13 +31,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use crate::{ - consts::*, - error::Error, - key::{self, SlotId}, - serialization::*, - transaction::Transaction, - yubikey::YubiKey, - Buffer, + consts::*, error::Error, key::SlotId, serialization::*, transaction::Transaction, + yubikey::YubiKey, Buffer, }; use log::error; use zeroize::Zeroizing; @@ -100,7 +95,7 @@ impl AsRef<[u8]> for Certificate { /// Read certificate pub(crate) fn read_certificate(txn: &Transaction<'_>, slot: SlotId) -> Result { let mut len: usize = 0; - let object_id = key::slot_object(slot)?; + let object_id = slot.object_id(); let mut buf = match txn.fetch_object(object_id) { Ok(b) => b, @@ -141,7 +136,7 @@ pub(crate) fn write_certificate( let mut buf = [0u8; CB_OBJ_MAX]; let mut offset = 0; - let object_id = key::slot_object(slot)?; + let object_id = slot.object_id(); if data.is_none() { return txn.save_object(object_id, &[]); diff --git a/src/consts.rs b/src/consts.rs index 75ef5ddb..2988342e 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -124,10 +124,6 @@ pub const TAG_ECC_POINT: u8 = 0x86; pub const YKPIV_ALGO_TAG: u8 = 0x80; pub const YKPIV_ALGO_3DES: u8 = 0x03; -pub const YKPIV_ALGO_RSA1024: u8 = 0x06; -pub const YKPIV_ALGO_RSA2048: u8 = 0x07; -pub const YKPIV_ALGO_ECCP256: u8 = 0x11; -pub const YKPIV_ALGO_ECCP384: u8 = 0x14; pub const YKPIV_ATR_NEO_R3: &[u8] = b";\xFC\x13\0\0\x811\xFE\x15YubikeyNEOr3\xE1\0"; @@ -141,72 +137,21 @@ pub const YKPIV_CCCID_SIZE: usize = 14; pub const YKPIV_CERTINFO_UNCOMPRESSED: u8 = 0; pub const YKPIV_CERTINFO_GZIP: u8 = 1; -pub const YKPIV_KEY_AUTHENTICATION: u8 = 0x9a; pub const YKPIV_KEY_CARDMGM: u8 = 0x9b; -pub const YKPIV_KEY_SIGNATURE: u8 = 0x9c; -pub const YKPIV_KEY_KEYMGM: u8 = 0x9d; -pub const YKPIV_KEY_CARDAUTH: u8 = 0x9e; -pub const YKPIV_KEY_RETIRED1: u8 = 0x82; -pub const YKPIV_KEY_RETIRED2: u8 = 0x83; -pub const YKPIV_KEY_RETIRED3: u8 = 0x84; -pub const YKPIV_KEY_RETIRED4: u8 = 0x85; -pub const YKPIV_KEY_RETIRED5: u8 = 0x86; -pub const YKPIV_KEY_RETIRED6: u8 = 0x87; -pub const YKPIV_KEY_RETIRED7: u8 = 0x88; -pub const YKPIV_KEY_RETIRED8: u8 = 0x89; -pub const YKPIV_KEY_RETIRED9: u8 = 0x8a; -pub const YKPIV_KEY_RETIRED10: u8 = 0x8b; -pub const YKPIV_KEY_RETIRED11: u8 = 0x8c; -pub const YKPIV_KEY_RETIRED12: u8 = 0x8d; -pub const YKPIV_KEY_RETIRED13: u8 = 0x8e; -pub const YKPIV_KEY_RETIRED14: u8 = 0x8f; -pub const YKPIV_KEY_RETIRED15: u8 = 0x90; -pub const YKPIV_KEY_RETIRED16: u8 = 0x91; -pub const YKPIV_KEY_RETIRED17: u8 = 0x92; -pub const YKPIV_KEY_RETIRED18: u8 = 0x93; -pub const YKPIV_KEY_RETIRED19: u8 = 0x94; -pub const YKPIV_KEY_RETIRED20: u8 = 0x95; -pub const YKPIV_KEY_ATTESTATION: u8 = 0xf9; pub const YKPIV_OBJ_CAPABILITY: u32 = 0x005f_c107; pub const YKPIV_OBJ_CHUID: u32 = 0x005f_c102; -pub const YKPIV_OBJ_AUTHENTICATION: u32 = 0x005f_c105; // cert for 9a key pub const YKPIV_OBJ_FINGERPRINTS: u32 = 0x005f_c103; pub const YKPIV_OBJ_SECURITY: u32 = 0x005f_c106; pub const YKPIV_OBJ_FACIAL: u32 = 0x005f_c108; pub const YKPIV_OBJ_PRINTED: u32 = 0x005f_c109; -pub const YKPIV_OBJ_SIGNATURE: u32 = 0x005f_c10a; // cert for 9c key -pub const YKPIV_OBJ_KEY_MANAGEMENT: u32 = 0x005f_c10b; // cert for 9d key -pub const YKPIV_OBJ_CARD_AUTH: u32 = 0x005f_c101; // cert for 9e key pub const YKPIV_OBJ_DISCOVERY: u32 = 0x7e; pub const YKPIV_OBJ_KEY_HISTORY: u32 = 0x005f_c10c; pub const YKPIV_OBJ_IRIS: u32 = 0x005f_c121; -pub const YKPIV_OBJ_RETIRED1: u32 = 0x005f_c10d; -pub const YKPIV_OBJ_RETIRED2: u32 = 0x005f_c10e; -pub const YKPIV_OBJ_RETIRED3: u32 = 0x005f_c10f; -pub const YKPIV_OBJ_RETIRED4: u32 = 0x005f_c110; -pub const YKPIV_OBJ_RETIRED5: u32 = 0x005f_c111; -pub const YKPIV_OBJ_RETIRED6: u32 = 0x005f_c112; -pub const YKPIV_OBJ_RETIRED7: u32 = 0x005f_c113; -pub const YKPIV_OBJ_RETIRED8: u32 = 0x005f_c114; -pub const YKPIV_OBJ_RETIRED9: u32 = 0x005f_c115; -pub const YKPIV_OBJ_RETIRED10: u32 = 0x005f_c116; -pub const YKPIV_OBJ_RETIRED11: u32 = 0x005f_c117; -pub const YKPIV_OBJ_RETIRED12: u32 = 0x005f_c118; -pub const YKPIV_OBJ_RETIRED13: u32 = 0x005f_c119; -pub const YKPIV_OBJ_RETIRED14: u32 = 0x005f_c11a; -pub const YKPIV_OBJ_RETIRED15: u32 = 0x005f_c11b; -pub const YKPIV_OBJ_RETIRED16: u32 = 0x005f_c11c; -pub const YKPIV_OBJ_RETIRED17: u32 = 0x005f_c11d; -pub const YKPIV_OBJ_RETIRED18: u32 = 0x005f_c11e; -pub const YKPIV_OBJ_RETIRED19: u32 = 0x005f_c11f; -pub const YKPIV_OBJ_RETIRED20: u32 = 0x005f_c120; - // Internal object IDs pub const YKPIV_OBJ_ADMIN_DATA: u32 = 0x005f_ff00; -pub const YKPIV_OBJ_ATTESTATION: u32 = 0x005f_ff01; pub const YKPIV_OBJ_MSCMAP: u32 = 0x005f_ff10; pub const YKPIV_OBJ_MSROOTS1: u32 = 0x005f_ff11; pub const YKPIV_OBJ_MSROOTS2: u32 = 0x005f_ff12; diff --git a/src/container.rs b/src/container.rs index ee5d8d32..56c48980 100644 --- a/src/container.rs +++ b/src/container.rs @@ -158,7 +158,7 @@ impl Container { Ok(Container { name, - slot: bytes[name_bytes_len], + slot: bytes[name_bytes_len].try_into()?, key_spec: bytes[name_bytes_len + 1], key_size_bits: u16::from_le_bytes( bytes[(name_bytes_len + 2)..(name_bytes_len + 4)] @@ -185,7 +185,7 @@ impl Container { bytes.extend_from_slice(&self.name[i].to_le_bytes()); } - bytes.push(self.slot); + bytes.push(self.slot.into()); bytes.push(self.key_spec); bytes.extend_from_slice(&self.key_size_bits.to_le_bytes()); bytes.push(self.flags); @@ -204,7 +204,7 @@ impl Debug for Container { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "PivContainer {{ name: {:?}, slot: {}, key_spec: {}, key_size_bits: {}, \ + "PivContainer {{ name: {:?}, slot: {:?}, key_spec: {}, key_size_bits: {}, \ flags: {}, pin_id: {}, associated_echd_container: {}, cert_fingerprint: {:?} }}", &self.name[..], self.slot, diff --git a/src/key.rs b/src/key.rs index 8c07e158..96392c77 100644 --- a/src/key.rs +++ b/src/key.rs @@ -45,61 +45,272 @@ use crate::{ serialization::*, settings, yubikey::YubiKey, - AlgorithmId, Buffer, ObjectId, + Buffer, ObjectId, }; use log::{debug, error, warn}; +use std::convert::TryFrom; /// Slot identifiers. /// -// TODO(tarcieri): replace these with enums -pub type SlotId = u8; - -/// Get the [`ObjectId`] that corresponds to a given [`SlotId`] -// TODO(tarcieri): factor this into a slot ID enum -pub(crate) fn slot_object(slot: SlotId) -> Result { - let id = match slot { - YKPIV_KEY_AUTHENTICATION => YKPIV_OBJ_AUTHENTICATION, - YKPIV_KEY_SIGNATURE => YKPIV_OBJ_SIGNATURE, - YKPIV_KEY_KEYMGM => YKPIV_OBJ_KEY_MANAGEMENT, - YKPIV_KEY_CARDAUTH => YKPIV_OBJ_CARD_AUTH, - YKPIV_KEY_ATTESTATION => YKPIV_OBJ_ATTESTATION, - slot if slot >= YKPIV_KEY_RETIRED1 && (slot <= YKPIV_KEY_RETIRED20) => { - YKPIV_OBJ_RETIRED1 + (slot - YKPIV_KEY_RETIRED1) as u32 +#[derive(Clone, Copy, Debug)] +pub enum SlotId { + /// This certificate and its associated private key is used to authenticate the card + /// and the cardholder. This slot is used for things like system login. The end user + /// PIN is required to perform any private key operations. Once the PIN has been + /// provided successfully, multiple private key operations may be performed without + /// additional cardholder consent. + Authentication, + + /// This certificate and its associated private key is used for digital signatures for + /// the purpose of document signing, or signing files and executables. The end user + /// PIN is required to perform any private key operations. The PIN must be submitted + /// every time immediately before a sign operation, to ensure cardholder participation + /// for every digital signature generated. + Signature, + + /// This certificate and its associated private key is used for encryption for the + /// purpose of confidentiality. This slot is used for things like encrypting e-mails + /// or files. The end user PIN is required to perform any private key operations. Once + /// the PIN has been provided successfully, multiple private key operations may be + /// performed without additional cardholder consent. + KeyManagement, + + /// This certificate and its associated private key is used to support additional + /// physical access applications, such as providing physical access to buildings via + /// PIV-enabled door locks. The end user PIN is NOT required to perform private key + /// operations for this slot. + CardAuthentication, + + /// These slots are only available on the YubiKey 4 & 5. They are meant for previously + /// used Key Management keys to be able to decrypt earlier encrypted documents or + /// emails. In the YubiKey 4 & 5 all 20 of them are fully available for use. + Retired(RetiredSlotId), + + /// This slot is only available on YubiKey version 4.3 and newer. It is only used for + /// attestation of other keys generated on device with instruction `f9`. This slot is + /// not cleared on reset, but can be overwritten. + Attestation, +} + +impl TryFrom for SlotId { + type Error = Error; + + fn try_from(value: u8) -> Result { + match value { + 0x9a => Ok(SlotId::Authentication), + 0x9c => Ok(SlotId::Signature), + 0x9d => Ok(SlotId::KeyManagement), + 0x9e => Ok(SlotId::CardAuthentication), + 0xf9 => Ok(SlotId::Attestation), + _ => RetiredSlotId::try_from(value).map(SlotId::Retired), + } + } +} + +impl From for u8 { + fn from(slot: SlotId) -> u8 { + match slot { + SlotId::Authentication => 0x9a, + SlotId::Signature => 0x9c, + SlotId::KeyManagement => 0x9d, + SlotId::CardAuthentication => 0x9e, + SlotId::Retired(retired) => retired.into(), + SlotId::Attestation => 0xf9, } - _ => return Err(Error::InvalidObject), - }; + } +} + +impl SlotId { + /// Returns the [`ObjectId`] that corresponds to a given [`SlotId`]. + pub(crate) fn object_id(self) -> ObjectId { + match self { + SlotId::Authentication => 0x005f_c105, + SlotId::Signature => 0x005f_c10a, + SlotId::KeyManagement => 0x005f_c10b, + SlotId::CardAuthentication => 0x005f_c101, + SlotId::Retired(retired) => retired.object_id(), + SlotId::Attestation => 0x005f_ff01, + } + } +} - Ok(id) +/// Retired slot IDs. +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug)] +pub enum RetiredSlotId { + R1, + R2, + R3, + R4, + R5, + R6, + R7, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, + R16, + R17, + R18, + R19, + R20, +} + +impl TryFrom for RetiredSlotId { + type Error = Error; + + fn try_from(value: u8) -> Result { + match value { + 0x82 => Ok(RetiredSlotId::R1), + 0x83 => Ok(RetiredSlotId::R2), + 0x84 => Ok(RetiredSlotId::R3), + 0x85 => Ok(RetiredSlotId::R4), + 0x86 => Ok(RetiredSlotId::R5), + 0x87 => Ok(RetiredSlotId::R6), + 0x88 => Ok(RetiredSlotId::R7), + 0x89 => Ok(RetiredSlotId::R8), + 0x8a => Ok(RetiredSlotId::R9), + 0x8b => Ok(RetiredSlotId::R10), + 0x8c => Ok(RetiredSlotId::R11), + 0x8d => Ok(RetiredSlotId::R12), + 0x8e => Ok(RetiredSlotId::R13), + 0x8f => Ok(RetiredSlotId::R14), + 0x90 => Ok(RetiredSlotId::R15), + 0x91 => Ok(RetiredSlotId::R16), + 0x92 => Ok(RetiredSlotId::R17), + 0x93 => Ok(RetiredSlotId::R18), + 0x94 => Ok(RetiredSlotId::R19), + 0x95 => Ok(RetiredSlotId::R20), + _ => Err(Error::InvalidObject), + } + } +} + +impl From for u8 { + fn from(slot: RetiredSlotId) -> u8 { + match slot { + RetiredSlotId::R1 => 0x82, + RetiredSlotId::R2 => 0x83, + RetiredSlotId::R3 => 0x84, + RetiredSlotId::R4 => 0x85, + RetiredSlotId::R5 => 0x86, + RetiredSlotId::R6 => 0x87, + RetiredSlotId::R7 => 0x88, + RetiredSlotId::R8 => 0x89, + RetiredSlotId::R9 => 0x8a, + RetiredSlotId::R10 => 0x8b, + RetiredSlotId::R11 => 0x8c, + RetiredSlotId::R12 => 0x8d, + RetiredSlotId::R13 => 0x8e, + RetiredSlotId::R14 => 0x8f, + RetiredSlotId::R15 => 0x90, + RetiredSlotId::R16 => 0x91, + RetiredSlotId::R17 => 0x92, + RetiredSlotId::R18 => 0x93, + RetiredSlotId::R19 => 0x94, + RetiredSlotId::R20 => 0x95, + } + } +} + +impl RetiredSlotId { + /// Returns the [`ObjectId`] that corresponds to a given [`RetiredSlotId`]. + pub(crate) fn object_id(self) -> ObjectId { + match self { + RetiredSlotId::R1 => 0x005f_c10d, + RetiredSlotId::R2 => 0x005f_c10e, + RetiredSlotId::R3 => 0x005f_c10f, + RetiredSlotId::R4 => 0x005f_c110, + RetiredSlotId::R5 => 0x005f_c111, + RetiredSlotId::R6 => 0x005f_c112, + RetiredSlotId::R7 => 0x005f_c113, + RetiredSlotId::R8 => 0x005f_c114, + RetiredSlotId::R9 => 0x005f_c115, + RetiredSlotId::R10 => 0x005f_c116, + RetiredSlotId::R11 => 0x005f_c117, + RetiredSlotId::R12 => 0x005f_c118, + RetiredSlotId::R13 => 0x005f_c119, + RetiredSlotId::R14 => 0x005f_c11a, + RetiredSlotId::R15 => 0x005f_c11b, + RetiredSlotId::R16 => 0x005f_c11c, + RetiredSlotId::R17 => 0x005f_c11d, + RetiredSlotId::R18 => 0x005f_c11e, + RetiredSlotId::R19 => 0x005f_c11f, + RetiredSlotId::R20 => 0x005f_c120, + } + } } /// Personal Identity Verification (PIV) key slots -pub const SLOTS: [u8; 24] = [ - YKPIV_KEY_AUTHENTICATION, - YKPIV_KEY_SIGNATURE, - YKPIV_KEY_KEYMGM, - YKPIV_KEY_RETIRED1, - YKPIV_KEY_RETIRED2, - YKPIV_KEY_RETIRED3, - YKPIV_KEY_RETIRED4, - YKPIV_KEY_RETIRED5, - YKPIV_KEY_RETIRED6, - YKPIV_KEY_RETIRED7, - YKPIV_KEY_RETIRED8, - YKPIV_KEY_RETIRED9, - YKPIV_KEY_RETIRED10, - YKPIV_KEY_RETIRED11, - YKPIV_KEY_RETIRED12, - YKPIV_KEY_RETIRED13, - YKPIV_KEY_RETIRED14, - YKPIV_KEY_RETIRED15, - YKPIV_KEY_RETIRED16, - YKPIV_KEY_RETIRED17, - YKPIV_KEY_RETIRED18, - YKPIV_KEY_RETIRED19, - YKPIV_KEY_RETIRED20, - YKPIV_KEY_CARDAUTH, +pub const SLOTS: [SlotId; 24] = [ + SlotId::Authentication, + SlotId::Signature, + SlotId::KeyManagement, + SlotId::Retired(RetiredSlotId::R1), + SlotId::Retired(RetiredSlotId::R2), + SlotId::Retired(RetiredSlotId::R3), + SlotId::Retired(RetiredSlotId::R4), + SlotId::Retired(RetiredSlotId::R5), + SlotId::Retired(RetiredSlotId::R6), + SlotId::Retired(RetiredSlotId::R7), + SlotId::Retired(RetiredSlotId::R8), + SlotId::Retired(RetiredSlotId::R9), + SlotId::Retired(RetiredSlotId::R10), + SlotId::Retired(RetiredSlotId::R11), + SlotId::Retired(RetiredSlotId::R12), + SlotId::Retired(RetiredSlotId::R13), + SlotId::Retired(RetiredSlotId::R14), + SlotId::Retired(RetiredSlotId::R15), + SlotId::Retired(RetiredSlotId::R16), + SlotId::Retired(RetiredSlotId::R17), + SlotId::Retired(RetiredSlotId::R18), + SlotId::Retired(RetiredSlotId::R19), + SlotId::Retired(RetiredSlotId::R20), + SlotId::CardAuthentication, ]; +/// Algorithm identifiers +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum AlgorithmId { + /// 1024-bit RSA. + Rsa1024, + /// 2048-bit RSA. + Rsa2048, + /// ECDSA with the NIST P256 curve. + EccP256, + /// ECDSA with the NIST P384 curve. + EccP384, +} + +impl TryFrom for AlgorithmId { + type Error = Error; + + fn try_from(value: u8) -> Result { + match value { + 0x06 => Ok(AlgorithmId::Rsa1024), + 0x07 => Ok(AlgorithmId::Rsa2048), + 0x11 => Ok(AlgorithmId::EccP256), + 0x14 => Ok(AlgorithmId::EccP384), + _ => Err(Error::AlgorithmError), + } + } +} + +impl From for u8 { + fn from(id: AlgorithmId) -> u8 { + match id { + AlgorithmId::Rsa1024 => 0x06, + AlgorithmId::Rsa2048 => 0x07, + AlgorithmId::EccP256 => 0x11, + AlgorithmId::EccP384 => 0x14, + } + } +} + /// PIV cryptographic keys stored in a YubiKey #[derive(Clone, Debug)] pub struct Key { @@ -120,13 +331,15 @@ impl Key { let buf = match certificate::read_certificate(&txn, slot) { Ok(b) => b, Err(e) => { - debug!("error reading certificate in slot {}: {}", slot, e); + debug!("error reading certificate in slot {:?}: {}", slot, e); continue; } }; - let cert = Certificate::new(buf)?; - keys.push(Key { slot, cert }); + if !buf.is_empty() { + let cert = Certificate::new(buf)?; + keys.push(Key { slot, cert }); + } } Ok(keys) @@ -202,55 +415,52 @@ pub fn generate( let mut templ = [0, Ins::GenerateAsymmetric.code(), 0, 0]; let setting_roca: settings::BoolValue; - if yubikey.device_model() == DEVTYPE_YK4 - && (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) - && yubikey.version.major == 4 - && (yubikey.version.minor < 3 || yubikey.version.minor == 3 && (yubikey.version.patch < 5)) - { - setting_roca = settings::BoolValue::get(SZ_SETTING_ROCA, true); - - let psz_msg = match setting_roca.source { - settings::Source::User => { - if setting_roca.value { - SZ_ROCA_ALLOW_USER - } else { - SZ_ROCA_BLOCK_USER - } - } - settings::Source::Admin => { - if setting_roca.value { - SZ_ROCA_ALLOW_ADMIN - } else { - SZ_ROCA_BLOCK_ADMIN + match algorithm { + AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => { + if yubikey.device_model() == DEVTYPE_YK4 + && yubikey.version.major == 4 + && (yubikey.version.minor < 3 + || yubikey.version.minor == 3 && (yubikey.version.patch < 5)) + { + setting_roca = settings::BoolValue::get(SZ_SETTING_ROCA, true); + + let psz_msg = match setting_roca.source { + settings::Source::User => { + if setting_roca.value { + SZ_ROCA_ALLOW_USER + } else { + SZ_ROCA_BLOCK_USER + } + } + settings::Source::Admin => { + if setting_roca.value { + SZ_ROCA_ALLOW_ADMIN + } else { + SZ_ROCA_BLOCK_ADMIN + } + } + _ => SZ_ROCA_DEFAULT, + }; + + warn!( + "YubiKey serial number {} is affected by vulnerability CVE-2017-15361 \ + (ROCA) and should be replaced. On-chip key generation {} See \ + YSA-2017-01 \ + for additional information on device replacement and mitigation assistance", + yubikey.serial, psz_msg + ); + + if !setting_roca.value { + return Err(Error::NotSupported); } } - _ => SZ_ROCA_DEFAULT, - }; - - warn!( - "YubiKey serial number {} is affected by vulnerability CVE-2017-15361 \ - (ROCA) and should be replaced. On-chip key generation {} See \ - YSA-2017-01 \ - for additional information on device replacement and mitigation assistance", - yubikey.serial, psz_msg - ); - - if !setting_roca.value { - return Err(Error::NotSupported); - } - } - - match algorithm { - YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 | YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => (), - _ => { - error!("invalid algorithm specified"); - return Err(Error::GenericError); } + _ => (), } let txn = yubikey.begin_transaction()?; - templ[3] = slot; + templ[3] = slot.into(); let mut offset = 5; in_data[..offset].copy_from_slice(&[ @@ -258,7 +468,7 @@ pub fn generate( 3, // length sans this 2-byte header YKPIV_ALGO_TAG, 1, - algorithm, + algorithm.into(), ]); if in_data[4] == 0 { @@ -312,7 +522,7 @@ pub fn generate( let data = Buffer::new(response.data().into()); match algorithm { - YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => { + AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => { let mut offset = 5; let mut len = 0; @@ -340,10 +550,10 @@ pub fn generate( exp, }) } - YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => { + AlgorithmId::EccP256 | AlgorithmId::EccP384 => { let mut offset = 3; - let len = if algorithm == YKPIV_ALGO_ECCP256 { + let len = if let AlgorithmId::EccP256 = algorithm { CB_ECC_POINTP256 } else { CB_ECC_POINTP384 @@ -367,9 +577,5 @@ pub fn generate( let point = data[offset..(offset + len)].to_vec(); Ok(GeneratedKey::Ecc { algorithm, point }) } - _ => { - error!("wrong algorithm"); - Err(Error::AlgorithmError) - } } } diff --git a/src/lib.rs b/src/lib.rs index b4d98515..37fd0c2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -167,10 +167,6 @@ pub mod yubikey; pub use self::{key::Key, mgm::MgmKey}; pub use yubikey::YubiKey; -/// Algorithm identifiers -// TODO(tarcieri): make this an enum -pub type AlgorithmId = u8; - /// Object identifiers pub type ObjectId = u32; diff --git a/src/transaction.rs b/src/transaction.rs index 68fa89fb..2514024b 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -9,6 +9,7 @@ use crate::{ use crate::{ apdu::{Response, StatusWords}, consts::*, + key::{AlgorithmId, SlotId}, mgm::MgmKey, serialization::*, Buffer, ObjectId, @@ -266,18 +267,18 @@ impl<'tx> Transaction<'tx> { pub(crate) fn authenticated_command( &self, sign_in: &[u8], - algorithm: u8, - key: u8, + algorithm: AlgorithmId, + key: SlotId, decipher: bool, ) -> Result { let in_len = sign_in.len(); let mut indata = [0u8; 1024]; - let templ = [0, Ins::Authenticate.code(), algorithm, key]; + let templ = [0, Ins::Authenticate.code(), algorithm.into(), key.into()]; let mut len: usize = 0; match algorithm { - YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => { - let key_len = if algorithm == YKPIV_ALGO_RSA1024 { + AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => { + let key_len = if let AlgorithmId::Rsa1024 = algorithm { 128 } else { 256 @@ -287,8 +288,8 @@ impl<'tx> Transaction<'tx> { return Err(Error::SizeError); } } - YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => { - let key_len = if algorithm == YKPIV_ALGO_ECCP256 { + AlgorithmId::EccP256 | AlgorithmId::EccP384 => { + let key_len = if let AlgorithmId::EccP256 = algorithm { 32 } else { 48 @@ -299,7 +300,6 @@ impl<'tx> Transaction<'tx> { return Err(Error::SizeError); } } - _ => return Err(Error::AlgorithmError), } let bytes = if in_len < 0x80 { @@ -314,12 +314,10 @@ impl<'tx> Transaction<'tx> { let mut offset = 1 + set_length(&mut indata[1..], in_len + bytes + 3); indata[offset] = 0x82; indata[offset + 1] = 0x00; - indata[offset + 2] = - if (algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384) && decipher { - 0x85 - } else { - 0x81 - }; + indata[offset + 2] = match (algorithm, decipher) { + (AlgorithmId::EccP256, true) | (AlgorithmId::EccP384, true) => 0x85, + _ => 0x81, + }; offset += 3; offset += set_length(&mut indata[offset..], in_len); diff --git a/src/yubikey.rs b/src/yubikey.rs index 2daf3c71..707e9caa 100644 --- a/src/yubikey.rs +++ b/src/yubikey.rs @@ -36,7 +36,7 @@ #[cfg(feature = "untested")] use crate::{ apdu::{Ins, StatusWords, APDU}, - key::SlotId, + key::{AlgorithmId, SlotId}, metadata, mgm::MgmKey, serialization::*, @@ -363,7 +363,7 @@ impl YubiKey { pub fn sign_data( &mut self, raw_in: &[u8], - algorithm: u8, + algorithm: AlgorithmId, key: SlotId, ) -> Result { let txn = self.begin_transaction()?; @@ -377,7 +377,7 @@ impl YubiKey { pub fn decrypt_data( &mut self, input: &[u8], - algorithm: u8, + algorithm: AlgorithmId, key: SlotId, ) -> Result { let txn = self.begin_transaction()?; @@ -605,7 +605,7 @@ impl YubiKey { pub fn import_private_key( &mut self, key: SlotId, - algorithm: u8, + algorithm: AlgorithmId, p: Option<&[u8]>, q: Option<&[u8]>, dp: Option<&[u8]>, @@ -616,15 +616,7 @@ impl YubiKey { touch_policy: u8, ) -> Result<(), Error> { let mut key_data = Zeroizing::new(vec![0u8; 1024]); - let templ = [0, Ins::ImportKey.code(), algorithm, key]; - - if key == YKPIV_KEY_CARDMGM - || key < YKPIV_KEY_RETIRED1 - || (key > YKPIV_KEY_RETIRED20 && key < YKPIV_KEY_AUTHENTICATION) - || (key > YKPIV_KEY_CARDAUTH && key != YKPIV_KEY_ATTESTATION) - { - return Err(Error::KeyError); - } + let templ = [0, Ins::ImportKey.code(), algorithm.into(), key.into()]; if pin_policy != YKPIV_PINPOLICY_DEFAULT && pin_policy != YKPIV_PINPOLICY_NEVER @@ -643,7 +635,7 @@ impl YubiKey { } let (elem_len, params, param_tag) = match algorithm { - YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => match (p, q, dp, dq, qinv) { + AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => match (p, q, dp, dq, qinv) { (Some(p), Some(q), Some(dp), Some(dq), Some(qinv)) => { if p.len() + q.len() + dp.len() + dq.len() + qinv.len() >= key_data.len() { return Err(Error::SizeError); @@ -651,8 +643,8 @@ impl YubiKey { ( match algorithm { - YKPIV_ALGO_RSA1024 => 64, - YKPIV_ALGO_RSA2048 => 128, + AlgorithmId::Rsa1024 => 64, + AlgorithmId::Rsa2048 => 128, _ => unreachable!(), }, vec![p, q, dp, dq, qinv], @@ -661,7 +653,7 @@ impl YubiKey { } _ => return Err(Error::GenericError), }, - YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => match ec_data { + AlgorithmId::EccP256 | AlgorithmId::EccP384 => match ec_data { Some(ec_data) => { if ec_data.len() >= key_data.len() { // This can never be true, but check to be explicit. @@ -670,8 +662,8 @@ impl YubiKey { ( match algorithm { - YKPIV_ALGO_ECCP256 => 32, - YKPIV_ALGO_ECCP384 => 48, + AlgorithmId::EccP256 => 32, + AlgorithmId::EccP384 => 48, _ => unreachable!(), }, vec![ec_data], @@ -680,7 +672,6 @@ impl YubiKey { } _ => return Err(Error::GenericError), }, - _ => return Err(Error::AlgorithmError), }; let mut offset = 0; @@ -737,7 +728,7 @@ impl YubiKey { /// #[cfg(feature = "untested")] pub fn attest(&mut self, key: SlotId) -> Result { - let templ = [0, Ins::Attest.code(), key, 0]; + let templ = [0, Ins::Attest.code(), key.into(), 0]; let txn = self.begin_transaction()?; let response = txn.transfer_data(&templ, &[], CB_OBJ_MAX)?;