Convert AlgorithmId into an enum

3DES also has an algorithm ID, but it is completely disjoint from the
key algorithms, and can be handled separately later.
This commit is contained in:
Jack Grigg
2019-11-30 19:36:09 +00:00
parent 12b5bd1e3c
commit afca0fec0a
5 changed files with 104 additions and 85 deletions
-4
View File
@@ -124,10 +124,6 @@ pub const TAG_ECC_POINT: u8 = 0x86;
pub const YKPIV_ALGO_TAG: u8 = 0x80; pub const YKPIV_ALGO_TAG: u8 = 0x80;
pub const YKPIV_ALGO_3DES: u8 = 0x03; 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"; pub const YKPIV_ATR_NEO_R3: &[u8] = b";\xFC\x13\0\0\x811\xFE\x15YubikeyNEOr3\xE1\0";
+48 -17
View File
@@ -45,7 +45,7 @@ use crate::{
serialization::*, serialization::*,
settings, settings,
yubikey::YubiKey, yubikey::YubiKey,
AlgorithmId, Buffer, ObjectId, Buffer, ObjectId,
}; };
use log::{debug, error, warn}; use log::{debug, error, warn};
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -273,6 +273,44 @@ pub const SLOTS: [SlotId; 24] = [
SlotId::CardAuthentication, 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<u8> for AlgorithmId {
type Error = Error;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0x06 => Ok(AlgorithmId::Rsa1024),
0x07 => Ok(AlgorithmId::Rsa2048),
0x11 => Ok(AlgorithmId::EccP256),
0x14 => Ok(AlgorithmId::EccP384),
_ => Err(Error::AlgorithmError),
}
}
}
impl From<AlgorithmId> 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 /// PIV cryptographic keys stored in a YubiKey
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Key { pub struct Key {
@@ -377,10 +415,12 @@ pub fn generate(
let mut templ = [0, Ins::GenerateAsymmetric.code(), 0, 0]; let mut templ = [0, Ins::GenerateAsymmetric.code(), 0, 0];
let setting_roca: settings::BoolValue; let setting_roca: settings::BoolValue;
match algorithm {
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
if yubikey.device_model() == DEVTYPE_YK4 if yubikey.device_model() == DEVTYPE_YK4
&& (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048)
&& yubikey.version.major == 4 && yubikey.version.major == 4
&& (yubikey.version.minor < 3 || yubikey.version.minor == 3 && (yubikey.version.patch < 5)) && (yubikey.version.minor < 3
|| yubikey.version.minor == 3 && (yubikey.version.patch < 5))
{ {
setting_roca = settings::BoolValue::get(SZ_SETTING_ROCA, true); setting_roca = settings::BoolValue::get(SZ_SETTING_ROCA, true);
@@ -414,13 +454,8 @@ pub fn generate(
return Err(Error::NotSupported); 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()?; let txn = yubikey.begin_transaction()?;
@@ -433,7 +468,7 @@ pub fn generate(
3, // length sans this 2-byte header 3, // length sans this 2-byte header
YKPIV_ALGO_TAG, YKPIV_ALGO_TAG,
1, 1,
algorithm, algorithm.into(),
]); ]);
if in_data[4] == 0 { if in_data[4] == 0 {
@@ -487,7 +522,7 @@ pub fn generate(
let data = Buffer::new(response.data().into()); let data = Buffer::new(response.data().into());
match algorithm { match algorithm {
YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => { AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
let mut offset = 5; let mut offset = 5;
let mut len = 0; let mut len = 0;
@@ -515,10 +550,10 @@ pub fn generate(
exp, exp,
}) })
} }
YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => { AlgorithmId::EccP256 | AlgorithmId::EccP384 => {
let mut offset = 3; let mut offset = 3;
let len = if algorithm == YKPIV_ALGO_ECCP256 { let len = if let AlgorithmId::EccP256 = algorithm {
CB_ECC_POINTP256 CB_ECC_POINTP256
} else { } else {
CB_ECC_POINTP384 CB_ECC_POINTP384
@@ -542,9 +577,5 @@ pub fn generate(
let point = data[offset..(offset + len)].to_vec(); let point = data[offset..(offset + len)].to_vec();
Ok(GeneratedKey::Ecc { algorithm, point }) Ok(GeneratedKey::Ecc { algorithm, point })
} }
_ => {
error!("wrong algorithm");
Err(Error::AlgorithmError)
}
} }
} }
-4
View File
@@ -167,10 +167,6 @@ pub mod yubikey;
pub use self::{key::Key, mgm::MgmKey}; pub use self::{key::Key, mgm::MgmKey};
pub use yubikey::YubiKey; pub use yubikey::YubiKey;
/// Algorithm identifiers
// TODO(tarcieri): make this an enum
pub type AlgorithmId = u8;
/// Object identifiers /// Object identifiers
pub type ObjectId = u32; pub type ObjectId = u32;
+10 -13
View File
@@ -9,7 +9,7 @@ use crate::{
use crate::{ use crate::{
apdu::{Response, StatusWords}, apdu::{Response, StatusWords},
consts::*, consts::*,
key::SlotId, key::{AlgorithmId, SlotId},
mgm::MgmKey, mgm::MgmKey,
serialization::*, serialization::*,
Buffer, ObjectId, Buffer, ObjectId,
@@ -267,18 +267,18 @@ impl<'tx> Transaction<'tx> {
pub(crate) fn authenticated_command( pub(crate) fn authenticated_command(
&self, &self,
sign_in: &[u8], sign_in: &[u8],
algorithm: u8, algorithm: AlgorithmId,
key: SlotId, key: SlotId,
decipher: bool, decipher: bool,
) -> Result<Buffer, Error> { ) -> Result<Buffer, Error> {
let in_len = sign_in.len(); let in_len = sign_in.len();
let mut indata = [0u8; 1024]; let mut indata = [0u8; 1024];
let templ = [0, Ins::Authenticate.code(), algorithm, key.into()]; let templ = [0, Ins::Authenticate.code(), algorithm.into(), key.into()];
let mut len: usize = 0; let mut len: usize = 0;
match algorithm { match algorithm {
YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => { AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
let key_len = if algorithm == YKPIV_ALGO_RSA1024 { let key_len = if let AlgorithmId::Rsa1024 = algorithm {
128 128
} else { } else {
256 256
@@ -288,8 +288,8 @@ impl<'tx> Transaction<'tx> {
return Err(Error::SizeError); return Err(Error::SizeError);
} }
} }
YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => { AlgorithmId::EccP256 | AlgorithmId::EccP384 => {
let key_len = if algorithm == YKPIV_ALGO_ECCP256 { let key_len = if let AlgorithmId::EccP256 = algorithm {
32 32
} else { } else {
48 48
@@ -300,7 +300,6 @@ impl<'tx> Transaction<'tx> {
return Err(Error::SizeError); return Err(Error::SizeError);
} }
} }
_ => return Err(Error::AlgorithmError),
} }
let bytes = if in_len < 0x80 { let bytes = if in_len < 0x80 {
@@ -315,11 +314,9 @@ impl<'tx> Transaction<'tx> {
let mut offset = 1 + set_length(&mut indata[1..], in_len + bytes + 3); let mut offset = 1 + set_length(&mut indata[1..], in_len + bytes + 3);
indata[offset] = 0x82; indata[offset] = 0x82;
indata[offset + 1] = 0x00; indata[offset + 1] = 0x00;
indata[offset + 2] = indata[offset + 2] = match (algorithm, decipher) {
if (algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384) && decipher { (AlgorithmId::EccP256, true) | (AlgorithmId::EccP384, true) => 0x85,
0x85 _ => 0x81,
} else {
0x81
}; };
offset += 3; offset += 3;
+11 -12
View File
@@ -36,7 +36,7 @@
#[cfg(feature = "untested")] #[cfg(feature = "untested")]
use crate::{ use crate::{
apdu::{Ins, StatusWords, APDU}, apdu::{Ins, StatusWords, APDU},
key::SlotId, key::{AlgorithmId, SlotId},
metadata, metadata,
mgm::MgmKey, mgm::MgmKey,
serialization::*, serialization::*,
@@ -356,7 +356,7 @@ impl YubiKey {
pub fn sign_data( pub fn sign_data(
&mut self, &mut self,
raw_in: &[u8], raw_in: &[u8],
algorithm: u8, algorithm: AlgorithmId,
key: SlotId, key: SlotId,
) -> Result<Buffer, Error> { ) -> Result<Buffer, Error> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
@@ -370,7 +370,7 @@ impl YubiKey {
pub fn decrypt_data( pub fn decrypt_data(
&mut self, &mut self,
input: &[u8], input: &[u8],
algorithm: u8, algorithm: AlgorithmId,
key: SlotId, key: SlotId,
) -> Result<Buffer, Error> { ) -> Result<Buffer, Error> {
let txn = self.begin_transaction()?; let txn = self.begin_transaction()?;
@@ -598,7 +598,7 @@ impl YubiKey {
pub fn import_private_key( pub fn import_private_key(
&mut self, &mut self,
key: SlotId, key: SlotId,
algorithm: u8, algorithm: AlgorithmId,
p: Option<&[u8]>, p: Option<&[u8]>,
q: Option<&[u8]>, q: Option<&[u8]>,
dp: Option<&[u8]>, dp: Option<&[u8]>,
@@ -609,7 +609,7 @@ impl YubiKey {
touch_policy: u8, touch_policy: u8,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut key_data = Zeroizing::new(vec![0u8; 1024]); let mut key_data = Zeroizing::new(vec![0u8; 1024]);
let templ = [0, Ins::ImportKey.code(), algorithm, key.into()]; let templ = [0, Ins::ImportKey.code(), algorithm.into(), key.into()];
// Only slot we want to exclude is CardManagement, which isn't in the enum. // Only slot we want to exclude is CardManagement, which isn't in the enum.
// TODO: Decide whether to add it or not. // TODO: Decide whether to add it or not.
@@ -634,7 +634,7 @@ impl YubiKey {
} }
let (elem_len, params, param_tag) = match algorithm { 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)) => { (Some(p), Some(q), Some(dp), Some(dq), Some(qinv)) => {
if p.len() + q.len() + dp.len() + dq.len() + qinv.len() >= key_data.len() { if p.len() + q.len() + dp.len() + dq.len() + qinv.len() >= key_data.len() {
return Err(Error::SizeError); return Err(Error::SizeError);
@@ -642,8 +642,8 @@ impl YubiKey {
( (
match algorithm { match algorithm {
YKPIV_ALGO_RSA1024 => 64, AlgorithmId::Rsa1024 => 64,
YKPIV_ALGO_RSA2048 => 128, AlgorithmId::Rsa2048 => 128,
_ => unreachable!(), _ => unreachable!(),
}, },
vec![p, q, dp, dq, qinv], vec![p, q, dp, dq, qinv],
@@ -652,7 +652,7 @@ impl YubiKey {
} }
_ => return Err(Error::GenericError), _ => return Err(Error::GenericError),
}, },
YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => match ec_data { AlgorithmId::EccP256 | AlgorithmId::EccP384 => match ec_data {
Some(ec_data) => { Some(ec_data) => {
if ec_data.len() >= key_data.len() { if ec_data.len() >= key_data.len() {
// This can never be true, but check to be explicit. // This can never be true, but check to be explicit.
@@ -661,8 +661,8 @@ impl YubiKey {
( (
match algorithm { match algorithm {
YKPIV_ALGO_ECCP256 => 32, AlgorithmId::EccP256 => 32,
YKPIV_ALGO_ECCP384 => 48, AlgorithmId::EccP384 => 48,
_ => unreachable!(), _ => unreachable!(),
}, },
vec![ec_data], vec![ec_data],
@@ -671,7 +671,6 @@ impl YubiKey {
} }
_ => return Err(Error::GenericError), _ => return Err(Error::GenericError),
}, },
_ => return Err(Error::AlgorithmError),
}; };
let mut offset = 0; let mut offset = 0;