Merge pull request #44 from str4d/more-enums
Convert SlotId and AlgorithmId into enums
This commit is contained in:
+4
-9
@@ -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<Buffer, Error> {
|
||||
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, &[]);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+3
-3
@@ -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,
|
||||
|
||||
+266
-60
@@ -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.
|
||||
/// <https://developers.yubico.com/PIV/Introduction/Certificate_slots.html>
|
||||
// TODO(tarcieri): replace these with enums
|
||||
pub type SlotId = u8;
|
||||
#[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,
|
||||
|
||||
/// 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<ObjectId, Error> {
|
||||
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
|
||||
/// 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,
|
||||
}
|
||||
_ => return Err(Error::InvalidObject),
|
||||
};
|
||||
|
||||
Ok(id)
|
||||
impl TryFrom<u8> for SlotId {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
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<SlotId> 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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<u8> for RetiredSlotId {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
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<RetiredSlotId> 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<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 {
|
||||
@@ -120,14 +331,16 @@ 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;
|
||||
}
|
||||
};
|
||||
|
||||
if !buf.is_empty() {
|
||||
let cert = Certificate::new(buf)?;
|
||||
keys.push(Key { slot, cert });
|
||||
}
|
||||
}
|
||||
|
||||
Ok(keys)
|
||||
}
|
||||
@@ -202,10 +415,12 @@ pub fn generate(
|
||||
let mut templ = [0, Ins::GenerateAsymmetric.code(), 0, 0];
|
||||
let setting_roca: settings::BoolValue;
|
||||
|
||||
match algorithm {
|
||||
AlgorithmId::Rsa1024 | AlgorithmId::Rsa2048 => {
|
||||
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))
|
||||
&& (yubikey.version.minor < 3
|
||||
|| yubikey.version.minor == 3 && (yubikey.version.patch < 5))
|
||||
{
|
||||
setting_roca = settings::BoolValue::get(SZ_SETTING_ROCA, true);
|
||||
|
||||
@@ -239,18 +454,13 @@ pub fn generate(
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
-13
@@ -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<Buffer, Error> {
|
||||
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,11 +314,9 @@ 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;
|
||||
|
||||
+12
-21
@@ -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<Buffer, Error> {
|
||||
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<Buffer, Error> {
|
||||
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 {
|
||||
/// <https://developers.yubico.com/PIV/Introduction/PIV_attestation.html>
|
||||
#[cfg(feature = "untested")]
|
||||
pub fn attest(&mut self, key: SlotId) -> Result<Buffer, Error> {
|
||||
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)?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user