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_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";
+82 -51
View File
@@ -45,7 +45,7 @@ use crate::{
serialization::*,
settings,
yubikey::YubiKey,
AlgorithmId, Buffer, ObjectId,
Buffer, ObjectId,
};
use log::{debug, error, warn};
use std::convert::TryFrom;
@@ -273,6 +273,44 @@ pub const SLOTS: [SlotId; 24] = [
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
#[derive(Clone, Debug)]
pub struct Key {
@@ -377,50 +415,47 @@ 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
}
}
_ => 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 <https://www.yubico.com/support/security-advisories/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);
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 <https://www.yubico.com/support/security-advisories/ysa-2017-01/> \
for additional information on device replacement and mitigation assistance",
yubikey.serial, psz_msg
);
if !setting_roca.value {
return Err(Error::NotSupported);
}
}
}
_ => (),
}
let txn = yubikey.begin_transaction()?;
@@ -433,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 {
@@ -487,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;
@@ -515,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
@@ -542,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)
}
}
}
-4
View File
@@ -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;
+11 -14
View File
@@ -9,7 +9,7 @@ use crate::{
use crate::{
apdu::{Response, StatusWords},
consts::*,
key::SlotId,
key::{AlgorithmId, SlotId},
mgm::MgmKey,
serialization::*,
Buffer, ObjectId,
@@ -267,18 +267,18 @@ impl<'tx> Transaction<'tx> {
pub(crate) fn authenticated_command(
&self,
sign_in: &[u8],
algorithm: u8,
algorithm: AlgorithmId,
key: SlotId,
decipher: bool,
) -> Result<Buffer, Error> {
let in_len = sign_in.len();
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;
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
@@ -288,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
@@ -300,7 +300,6 @@ impl<'tx> Transaction<'tx> {
return Err(Error::SizeError);
}
}
_ => return Err(Error::AlgorithmError),
}
let bytes = if in_len < 0x80 {
@@ -315,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);
+11 -12
View File
@@ -36,7 +36,7 @@
#[cfg(feature = "untested")]
use crate::{
apdu::{Ins, StatusWords, APDU},
key::SlotId,
key::{AlgorithmId, SlotId},
metadata,
mgm::MgmKey,
serialization::*,
@@ -356,7 +356,7 @@ impl YubiKey {
pub fn sign_data(
&mut self,
raw_in: &[u8],
algorithm: u8,
algorithm: AlgorithmId,
key: SlotId,
) -> Result<Buffer, Error> {
let txn = self.begin_transaction()?;
@@ -370,7 +370,7 @@ impl YubiKey {
pub fn decrypt_data(
&mut self,
input: &[u8],
algorithm: u8,
algorithm: AlgorithmId,
key: SlotId,
) -> Result<Buffer, Error> {
let txn = self.begin_transaction()?;
@@ -598,7 +598,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]>,
@@ -609,7 +609,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.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.
// TODO: Decide whether to add it or not.
@@ -634,7 +634,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);
@@ -642,8 +642,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],
@@ -652,7 +652,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.
@@ -661,8 +661,8 @@ impl YubiKey {
(
match algorithm {
YKPIV_ALGO_ECCP256 => 32,
YKPIV_ALGO_ECCP384 => 48,
AlgorithmId::EccP256 => 32,
AlgorithmId::EccP384 => 48,
_ => unreachable!(),
},
vec![ec_data],
@@ -671,7 +671,6 @@ impl YubiKey {
}
_ => return Err(Error::GenericError),
},
_ => return Err(Error::AlgorithmError),
};
let mut offset = 0;