use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PIVKeySlot {
Authentication = 0x9A,
CardManagement = 0x9B,
DigitalSignature = 0x9C,
KeyManagement = 0x9D,
CardAuthentication = 0x9E,
}
impl PIVKeySlot {
pub fn from_byte(byte: u8) -> Option<Self> {
match byte {
0x9A => Some(Self::Authentication),
0x9B => Some(Self::CardManagement),
0x9C => Some(Self::DigitalSignature),
0x9D => Some(Self::KeyManagement),
0x9E => Some(Self::CardAuthentication),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PIVAlgorithm {
TDES = 0x03,
RSA2048 = 0x07,
ECCP256 = 0x11,
ECCP384 = 0x14,
}
impl PIVAlgorithm {
pub fn from_byte(byte: u8) -> Option<Self> {
match byte {
0x03 => Some(Self::TDES),
0x07 => Some(Self::RSA2048),
0x11 => Some(Self::ECCP256),
0x14 => Some(Self::ECCP384),
_ => None,
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PIVKeyData {
pub algorithm: u8,
pub private_key: Vec<u8>,
pub public_key: Vec<u8>,
pub certificate: Vec<u8>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PIVDataObjects {
pub chuid: Vec<u8>,
pub ccc: Vec<u8>,
pub key_9a: PIVKeyData,
pub key_9c: PIVKeyData,
pub key_9d: PIVKeyData,
pub key_9e: PIVKeyData,
pub management_key: Vec<u8>,
pub pin: Vec<u8>,
pub puk: Vec<u8>,
pub pin_retries: u8,
pub puk_retries: u8,
pub printed_info: Vec<u8>,
pub discovery: Vec<u8>,
pub key_history: Vec<u8>,
}
impl PIVDataObjects {
pub const DEFAULT_MGMT_KEY: &'static [u8] = &[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
];
pub const DEFAULT_PIN: &'static [u8] = b"123456";
pub const DEFAULT_PUK: &'static [u8] = b"12345678";
pub fn new() -> Self {
Self {
chuid: Vec::new(),
ccc: Vec::new(),
key_9a: PIVKeyData::default(),
key_9c: PIVKeyData::default(),
key_9d: PIVKeyData::default(),
key_9e: PIVKeyData::default(),
management_key: Self::DEFAULT_MGMT_KEY.to_vec(),
pin: Self::DEFAULT_PIN.to_vec(),
puk: Self::DEFAULT_PUK.to_vec(),
pin_retries: 3,
puk_retries: 3,
printed_info: Vec::new(),
discovery: Vec::new(),
key_history: Vec::new(),
}
}
pub fn get_key(&self, slot: PIVKeySlot) -> Option<&PIVKeyData> {
match slot {
PIVKeySlot::Authentication => Some(&self.key_9a),
PIVKeySlot::DigitalSignature => Some(&self.key_9c),
PIVKeySlot::KeyManagement => Some(&self.key_9d),
PIVKeySlot::CardAuthentication => Some(&self.key_9e),
PIVKeySlot::CardManagement => None, }
}
pub fn get_key_mut(&mut self, slot: PIVKeySlot) -> Option<&mut PIVKeyData> {
match slot {
PIVKeySlot::Authentication => Some(&mut self.key_9a),
PIVKeySlot::DigitalSignature => Some(&mut self.key_9c),
PIVKeySlot::KeyManagement => Some(&mut self.key_9d),
PIVKeySlot::CardAuthentication => Some(&mut self.key_9e),
PIVKeySlot::CardManagement => None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_slot_from_byte() {
assert_eq!(PIVKeySlot::from_byte(0x9A), Some(PIVKeySlot::Authentication));
assert_eq!(PIVKeySlot::from_byte(0x9C), Some(PIVKeySlot::DigitalSignature));
assert_eq!(PIVKeySlot::from_byte(0xFF), None);
}
#[test]
fn test_default_credentials() {
let data = PIVDataObjects::new();
assert_eq!(data.management_key.len(), 24);
assert_eq!(data.pin, b"123456");
assert_eq!(data.puk, b"12345678");
}
}