use super::{
AeadAlgorithm, AtcaDeviceType, AtcaIfaceCfg, AtcaIfaceType, AtcaSlot, AtcaStatus,
AteccDeviceTrait, InfoCmdType, KeyType, NonceTarget, OutputProtectionState, SignMode,
VerifyMode,
};
use super::{ATCA_AES_DATA_SIZE, ATCA_RANDOM_BUFFER_SIZE, ATCA_SERIAL_NUM_SIZE};
use rand::{distributions::Standard, Rng};
pub struct AteccDevice {
dev_type: AtcaDeviceType,
}
impl Default for AteccDevice {
fn default() -> AteccDevice {
AteccDevice {
dev_type: AtcaDeviceType::AtcaTestDevNone,
}
}
}
impl AteccDeviceTrait for AteccDevice {
fn random(&self, rand_out: &mut Vec<u8>) -> AtcaStatus {
let vector: Vec<u8> = rand::thread_rng()
.sample_iter(Standard)
.take(ATCA_RANDOM_BUFFER_SIZE)
.collect();
rand_out.resize(ATCA_RANDOM_BUFFER_SIZE, 0u8);
rand_out.copy_from_slice(&vector);
match self.dev_type {
AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
AtcaStatus::AtcaSuccess
}
_ => AtcaStatus::AtcaUnimplemented,
}
}
fn sha(&self, _message: Vec<u8>, _digest: &mut Vec<u8>) -> AtcaStatus {
self.default_dev_status()
}
fn nonce(&self, _target: NonceTarget, _data: &[u8]) -> AtcaStatus {
self.default_dev_status()
}
fn nonce_rand(&self, _host_nonce: &[u8], _rand_out: &mut Vec<u8>) -> AtcaStatus {
self.default_dev_status()
}
fn gen_key(&self, _key_type: KeyType, _slot_id: u8) -> AtcaStatus {
self.default_dev_status()
}
fn import_key(&self, _key_type: KeyType, _key_data: &[u8], _slot_number: u8) -> AtcaStatus {
self.default_dev_status()
}
fn export_key(&self, _key_type: KeyType, _key_data: &mut Vec<u8>, _slot_id: u8) -> AtcaStatus {
self.default_dev_status()
}
fn get_public_key(&self, _slot_id: u8, _public_key: &mut Vec<u8>) -> AtcaStatus {
self.default_dev_status()
}
fn sign_hash(&self, _mode: SignMode, _slot_id: u8, _signature: &mut Vec<u8>) -> AtcaStatus {
self.default_dev_status()
}
fn verify_hash(
&self,
_mode: VerifyMode,
_hash: &[u8],
_signature: &[u8],
) -> Result<bool, AtcaStatus> {
match self.dev_type {
AtcaDeviceType::AtcaTestDevSuccess => Ok(true),
_ => Err(self.default_dev_status()),
}
}
fn aead_encrypt(
&self,
_algorithm: AeadAlgorithm,
_slot_id: u8,
_data: &mut [u8],
) -> Result<Vec<u8>, AtcaStatus> {
match self.dev_type {
AtcaDeviceType::AtcaTestDevSuccess => Ok(vec![0; ATCA_AES_DATA_SIZE]),
_ => Err(self.default_dev_status()),
}
}
fn aead_decrypt(
&self,
_algorithm: AeadAlgorithm,
_slot_id: u8,
_data: &mut [u8],
) -> Result<bool, AtcaStatus> {
match self.dev_type {
AtcaDeviceType::AtcaTestDevSuccess => Ok(true),
_ => Err(self.default_dev_status()),
}
}
fn get_device_type(&self) -> AtcaDeviceType {
self.dev_type
}
fn is_configuration_locked(&self) -> bool {
match self.dev_type {
AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
true
}
_ => false,
}
}
fn is_data_zone_locked(&self) -> bool {
matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
}
fn get_config(&self, _atca_slots: &mut Vec<AtcaSlot>) -> AtcaStatus {
match self.dev_type {
AtcaDeviceType::AtcaTestDevSuccess | AtcaDeviceType::AtcaTestDevFailUnimplemented => {
AtcaStatus::AtcaSuccess
}
_ => AtcaStatus::AtcaUnimplemented,
}
}
fn info_cmd(&self, _command: InfoCmdType) -> Result<Vec<u8>, AtcaStatus> {
match self.dev_type {
AtcaDeviceType::AtcaTestDevSuccess => Ok(Vec::new()),
_ => Err(self.default_dev_status()),
}
}
fn add_access_key(&self, _slot_id: u8, _encryption_key: &[u8]) -> AtcaStatus {
self.default_dev_status()
}
fn flush_access_keys(&self) -> AtcaStatus {
self.default_dev_status()
}
fn get_serial_number(&self) -> [u8; ATCA_SERIAL_NUM_SIZE] {
let mut serial_number = [0; ATCA_SERIAL_NUM_SIZE];
if AtcaDeviceType::AtcaTestDevSuccess == self.dev_type {
serial_number[0] = 0x01;
serial_number[1] = 0x23;
}
serial_number
}
fn is_aes_enabled(&self) -> bool {
matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
}
fn is_kdf_aes_enabled(&self) -> bool {
matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
}
fn is_io_protection_key_enabled(&self) -> bool {
matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
}
fn get_ecdh_output_protection_state(&self) -> OutputProtectionState {
OutputProtectionState::ClearTextAllowed
}
fn get_kdf_output_protection_state(&self) -> OutputProtectionState {
OutputProtectionState::ClearTextAllowed
}
fn release(&self) -> AtcaStatus {
match self.dev_type {
AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
AtcaStatus::AtcaSuccess
}
_ => AtcaStatus::AtcaUnimplemented,
}
}
#[cfg(test)]
fn read_zone(
&self,
_zone: u8,
_slot: u16,
_block: u8,
_offset: u8,
data: &mut Vec<u8>,
_len: u8,
) -> AtcaStatus {
data.clear();
self.default_dev_status()
}
#[cfg(test)]
fn read_config_zone(&self, _config_data: &mut Vec<u8>) -> AtcaStatus {
self.default_dev_status()
}
#[cfg(test)]
fn cmp_config_zone(&self, _config_data: &mut [u8]) -> Result<bool, AtcaStatus> {
match self.dev_type {
AtcaDeviceType::AtcaTestDevSuccess => Ok(true),
_ => Err(self.default_dev_status()),
}
}
#[cfg(test)]
fn get_access_key(&self, _slot_id: u8, _key: &mut Vec<u8>) -> AtcaStatus {
self.default_dev_status()
}
}
impl AteccDevice {
pub fn new(r_iface_cfg: AtcaIfaceCfg) -> Result<AteccDevice, String> {
let mut device = AteccDevice::default();
match r_iface_cfg.iface_type {
AtcaIfaceType::AtcaTestIface => (),
_ => {
let err = format!(
"Software implementation of an AteccDevice does not support interface {}",
r_iface_cfg.iface_type.to_string()
);
return Err(err);
}
}
device.dev_type = match r_iface_cfg.devtype {
AtcaDeviceType::AtcaTestDevFail => AtcaDeviceType::AtcaTestDevFail,
AtcaDeviceType::AtcaTestDevSuccess => AtcaDeviceType::AtcaTestDevSuccess,
AtcaDeviceType::AtcaTestDevFailUnimplemented => {
AtcaDeviceType::AtcaTestDevFailUnimplemented
}
_ => {
let err = format!(
"Software implementation of an AteccDevice does not support interface {}",
r_iface_cfg.devtype.to_string()
);
return Err(err);
}
};
Ok(device)
}
fn default_dev_status(&self) -> AtcaStatus {
match self.dev_type {
AtcaDeviceType::AtcaTestDevSuccess => AtcaStatus::AtcaSuccess,
_ => AtcaStatus::AtcaUnimplemented,
}
}
}