rust_cryptoauthlib/sw_impl/
mod.rs

1#[cfg(test)]
2use cryptoauthlib_sys::atca_aes_cbc_ctx_t;
3#[cfg(test)]
4use cryptoauthlib_sys::atca_aes_ctr_ctx_t;
5#[cfg(test)]
6use std::mem::MaybeUninit;
7
8use super::{
9    AeadAlgorithm, AtcaDeviceType, AtcaIfaceCfg, AtcaIfaceType, AtcaSlot, AtcaStatus,
10    AteccDeviceTrait, CipherAlgorithm, EcdhParams, EcdhResult, InfoCmdType, KdfAlgorithm,
11    KdfParams, KdfResult, KeyType, MacAlgorithm, NonceTarget, OutputProtectionState, SignMode,
12    VerifyMode,
13};
14
15#[cfg(test)]
16use super::AtcaSlotCapacity;
17
18use super::{ATCA_AES_DATA_SIZE, ATCA_RANDOM_BUFFER_SIZE, ATCA_SERIAL_NUM_SIZE};
19use rand::{distributions::Standard, Rng};
20
21pub struct AteccDevice {
22    dev_type: AtcaDeviceType,
23}
24
25// Software ATECC implements following functions:
26// new(), random(), get_device_type(), is_configuration_locked(), get_config(), release().
27// All aothers are considered to be mocked.
28// Depending on set device type they either:
29// - always fails
30// - always succeed
31// - fail if they are not implemented but only mocked.
32impl Default for AteccDevice {
33    fn default() -> AteccDevice {
34        AteccDevice {
35            dev_type: AtcaDeviceType::AtcaTestDevNone,
36        }
37    }
38}
39
40impl AteccDeviceTrait for AteccDevice {
41    fn random(&self, rand_out: &mut Vec<u8>) -> AtcaStatus {
42        let vector: Vec<u8> = rand::thread_rng()
43            .sample_iter(Standard)
44            .take(ATCA_RANDOM_BUFFER_SIZE)
45            .collect();
46        rand_out.resize(ATCA_RANDOM_BUFFER_SIZE, 0u8);
47        rand_out.copy_from_slice(&vector);
48        match self.dev_type {
49            AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
50                AtcaStatus::AtcaSuccess
51            }
52            _ => AtcaStatus::AtcaUnimplemented,
53        }
54    }
55    /// Request ATECC to compute a message hash (SHA256)
56    fn sha(&self, _message: Vec<u8>, _digest: &mut Vec<u8>) -> AtcaStatus {
57        self.default_dev_status()
58    }
59    /// Execute a Nonce command in pass-through mode to load one of the
60    /// device's internal buffers with a fixed value.
61    /// For the ATECC608A, available targets are TempKey (32 or 64 bytes), Message
62    /// Digest Buffer (32 or 64 bytes), or the Alternate Key Buffer (32 bytes). For
63    /// all other devices, only TempKey (32 bytes) is available.
64    fn nonce(&self, _target: NonceTarget, _data: &[u8]) -> AtcaStatus {
65        self.default_dev_status()
66    }
67    /// Execute a Nonce command to generate a random nonce combining a host
68    /// nonce and a device random number.
69    fn nonce_rand(&self, _host_nonce: &[u8], _rand_out: &mut Vec<u8>) -> AtcaStatus {
70        self.default_dev_status()
71    }
72    /// Request ATECC to generate a cryptographic key
73    fn gen_key(&self, _key_type: KeyType, _slot_id: u8) -> AtcaStatus {
74        self.default_dev_status()
75    }
76    /// Request ATECC to import a cryptographic key
77    fn import_key(&self, _key_type: KeyType, _key_data: &[u8], _slot_number: u8) -> AtcaStatus {
78        self.default_dev_status()
79    }
80    /// Request ATECC to export a cryptographic key
81    fn export_key(&self, _key_type: KeyType, _key_data: &mut Vec<u8>, _slot_id: u8) -> AtcaStatus {
82        self.default_dev_status()
83    }
84    /// Depending on the socket configuration, this function calculates
85    /// public key based on an existing private key in the socket
86    /// or exports the public key directly
87    fn get_public_key(&self, _slot_id: u8, _public_key: &mut Vec<u8>) -> AtcaStatus {
88        self.default_dev_status()
89    }
90    /// Request ATECC to generate an ECDSA signature
91    fn sign_hash(&self, _mode: SignMode, _slot_id: u8, _signature: &mut Vec<u8>) -> AtcaStatus {
92        self.default_dev_status()
93    }
94    /// Request ATECC to verify ECDSA signature
95    fn verify_hash(
96        &self,
97        _mode: VerifyMode,
98        _hash: &[u8],
99        _signature: &[u8],
100    ) -> Result<bool, AtcaStatus> {
101        match self.dev_type {
102            AtcaDeviceType::AtcaTestDevSuccess => Ok(true),
103            _ => Err(self.default_dev_status()),
104        }
105    }
106    /// Data encryption function in AES unauthenticated cipher alhorithms modes
107    fn cipher_encrypt(
108        &self,
109        _algorithm: CipherAlgorithm,
110        _slot_id: u8,
111        _data: &mut Vec<u8>,
112    ) -> AtcaStatus {
113        self.default_dev_status()
114    }
115    /// Data decryption function in AES unauthenticated cipher alhorithms modes
116    fn cipher_decrypt(
117        &self,
118        _algorithm: CipherAlgorithm,
119        _slot_id: u8,
120        _data: &mut Vec<u8>,
121    ) -> AtcaStatus {
122        self.default_dev_status()
123    }
124    /// Data encryption function in AES AEAD (authenticated encryption with associated data) modes
125    fn aead_encrypt(
126        &self,
127        _algorithm: AeadAlgorithm,
128        _slot_id: u8,
129        _data: &mut Vec<u8>,
130    ) -> Result<Vec<u8>, AtcaStatus> {
131        match self.dev_type {
132            AtcaDeviceType::AtcaTestDevSuccess => Ok(vec![0; ATCA_AES_DATA_SIZE]),
133            _ => Err(self.default_dev_status()),
134        }
135    }
136    /// Data decryption function in AES AEAD (authenticated encryption with associated data) modes
137    fn aead_decrypt(
138        &self,
139        _algorithm: AeadAlgorithm,
140        _slot_id: u8,
141        _data: &mut Vec<u8>,
142    ) -> Result<bool, AtcaStatus> {
143        match self.dev_type {
144            AtcaDeviceType::AtcaTestDevSuccess => Ok(true),
145            _ => Err(self.default_dev_status()),
146        }
147    }
148    /// A function that calculates the MAC (Message Authentication Code) value for a message
149    fn mac_compute(
150        &self,
151        _algorithm: MacAlgorithm,
152        _slot_id: u8,
153        _data: &[u8],
154    ) -> Result<Vec<u8>, AtcaStatus> {
155        match self.dev_type {
156            AtcaDeviceType::AtcaTestDevSuccess => Ok(vec![0; ATCA_AES_DATA_SIZE]),
157            _ => Err(self.default_dev_status()),
158        }
159    }
160    /// A function that verifies the value of MAC (Message Authentication Code) for a message
161    fn mac_verify(
162        &self,
163        _algorithm: MacAlgorithm,
164        _slot_id: u8,
165        _data: &[u8],
166    ) -> Result<bool, AtcaStatus> {
167        match self.dev_type {
168            AtcaDeviceType::AtcaTestDevSuccess => Ok(true),
169            _ => Err(self.default_dev_status()),
170        }
171    }
172    /// KDF command function, which derives a new key in PRF, AES, or HKDF modes
173    fn kdf(
174        &self,
175        _algorithm: KdfAlgorithm,
176        _parameters: KdfParams,
177        _message: Option<&[u8]>,
178        _message_length: usize,
179    ) -> Result<KdfResult, AtcaStatus> {
180        match self.dev_type {
181            AtcaDeviceType::AtcaTestDevSuccess => Ok(KdfResult {
182                out_data: None,
183                out_nonce: None,
184            }),
185            _ => Err(self.default_dev_status()),
186        }
187    }
188    /// Function for generating premaster secret key using ECDH
189    fn ecdh(
190        &self,
191        _parameters: EcdhParams,
192        _peer_public_key: &[u8],
193    ) -> Result<EcdhResult, AtcaStatus> {
194        match self.dev_type {
195            AtcaDeviceType::AtcaTestDevSuccess => Ok(EcdhResult {
196                pms: None,
197                out_nonce: None,
198            }),
199            _ => Err(self.default_dev_status()),
200        }
201    }
202    /// Execute this command prevents future modifications of the Configuration zone.
203    fn lock_config_zone(&self) -> AtcaStatus {
204        self.default_dev_status()
205    } // AteccDevice::lock_config_zone()
206    /// Execute this command prevents future modifications of the Data and OTP zones.
207    fn lock_data_zone(&self) -> AtcaStatus {
208        self.default_dev_status()
209    } // AteccDevice::lock_data_zone()
210    /// Lock an individual slot in the data zone on an ATECC device. Not available for ATSHA devices.
211    fn lock_slot(&self, _slot_id: u8) -> AtcaStatus {
212        self.default_dev_status()
213    } // AteccDevice::lock_slot()
214    /// Function for uploading configuration to the chip.
215    fn load_config_into_chip(&self, _config: &[u8]) -> AtcaStatus {
216        self.default_dev_status()
217    } // AteccDevice::load_config_into_chip()
218    /// Request ATECC to return own device type
219    fn get_device_type(&self) -> AtcaDeviceType {
220        self.dev_type
221    }
222    /// Request ATECC to check if its configuration is locked.
223    /// If true, a chip can be used for cryptographic operations
224    fn is_configuration_locked(&self) -> bool {
225        match self.dev_type {
226            AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
227                true
228            }
229            _ => false,
230        }
231    }
232    /// Request ATECC to check if its Data Zone is locked.
233    /// If true, a chip can be used for cryptographic operations
234    fn is_data_zone_locked(&self) -> bool {
235        matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
236    }
237    /// Returns a structure containing configuration data read from ATECC
238    /// during initialization of the AteccDevice object.
239    fn get_config(&self, _atca_slots: &mut Vec<AtcaSlot>) -> AtcaStatus {
240        match self.dev_type {
241            AtcaDeviceType::AtcaTestDevSuccess | AtcaDeviceType::AtcaTestDevFailUnimplemented => {
242                AtcaStatus::AtcaSuccess
243            }
244            _ => AtcaStatus::AtcaUnimplemented,
245        }
246    }
247    /// Command accesses some static or dynamic information from the ATECC chip
248    fn info_cmd(&self, _command: InfoCmdType) -> Result<Vec<u8>, AtcaStatus> {
249        match self.dev_type {
250            AtcaDeviceType::AtcaTestDevSuccess => Ok(Vec::new()),
251            _ => Err(self.default_dev_status()),
252        }
253    }
254
255    fn add_access_key(&self, _slot_id: u8, _encryption_key: &[u8]) -> AtcaStatus {
256        self.default_dev_status()
257    }
258
259    fn flush_access_keys(&self) -> AtcaStatus {
260        self.default_dev_status()
261    }
262
263    fn get_serial_number(&self) -> [u8; ATCA_SERIAL_NUM_SIZE] {
264        let mut serial_number = [0; ATCA_SERIAL_NUM_SIZE];
265        if AtcaDeviceType::AtcaTestDevSuccess == self.dev_type {
266            serial_number[0] = 0x01;
267            serial_number[1] = 0x23;
268        }
269
270        serial_number
271    }
272
273    fn is_aes_enabled(&self) -> bool {
274        matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
275    }
276
277    fn is_kdf_aes_enabled(&self) -> bool {
278        matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
279    }
280
281    fn is_kdf_iv_enabled(&self) -> bool {
282        matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
283    }
284
285    fn is_io_protection_key_enabled(&self) -> bool {
286        matches!(self.default_dev_status(), AtcaStatus::AtcaSuccess)
287    }
288
289    fn get_ecdh_output_protection_state(&self) -> OutputProtectionState {
290        OutputProtectionState::ClearTextAllowed
291    }
292
293    fn get_kdf_output_protection_state(&self) -> OutputProtectionState {
294        OutputProtectionState::ClearTextAllowed
295    }
296
297    /// invoke sleep on the CryptoAuth device
298    fn sleep(&self) -> AtcaStatus {
299        match self.dev_type {
300            AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
301                AtcaStatus::AtcaSuccess
302            }
303            _ => AtcaStatus::AtcaUnimplemented,
304        }
305    }
306
307    fn wakeup(&self) -> AtcaStatus {
308        match self.dev_type {
309            AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
310                AtcaStatus::AtcaSuccess
311            }
312            _ => AtcaStatus::AtcaUnimplemented,
313        }
314    }
315
316    /// ATECC device instance destructor
317    fn release(&self) -> AtcaStatus {
318        match self.dev_type {
319            AtcaDeviceType::AtcaTestDevFailUnimplemented | AtcaDeviceType::AtcaTestDevSuccess => {
320                AtcaStatus::AtcaSuccess
321            }
322            _ => AtcaStatus::AtcaUnimplemented,
323        }
324    }
325
326    //--------------------------------------------------
327    //
328    // Functions available only during testing
329    //
330    //--------------------------------------------------
331
332    /// A generic function that reads data from the chip
333    #[cfg(test)]
334    fn read_zone(
335        &self,
336        _zone: u8,
337        _slot: u16,
338        _block: u8,
339        _offset: u8,
340        _data: &mut [u8],
341    ) -> AtcaStatus {
342        self.default_dev_status()
343    }
344    /// Request ATECC to read and return own configuration zone.
345    /// Note: this function returns raw data, function get_config(..) implements a more
346    /// structured return value.
347    #[cfg(test)]
348    fn read_config_zone(&self, _config_data: &mut Vec<u8>) -> AtcaStatus {
349        self.default_dev_status()
350    }
351    /// Compare internal config zone contents vs. config_data.
352    /// Diagnostic function.
353    #[cfg(test)]
354    fn cmp_config_zone(&self, _config_data: &mut [u8]) -> Result<bool, AtcaStatus> {
355        match self.dev_type {
356            AtcaDeviceType::AtcaTestDevSuccess => Ok(true),
357            _ => Err(self.default_dev_status()),
358        }
359    }
360    #[cfg(test)]
361    fn get_access_key(&self, _slot_id: u8, _key: &mut Vec<u8>) -> AtcaStatus {
362        self.default_dev_status()
363    }
364    #[cfg(test)]
365    fn aes_encrypt_block(
366        &self,
367        _key_id: u16,
368        _key_block: u8,
369        _input: &[u8],
370    ) -> Result<[u8; ATCA_AES_DATA_SIZE], AtcaStatus> {
371        match self.dev_type {
372            AtcaDeviceType::AtcaTestDevSuccess => Ok([0x00; ATCA_AES_DATA_SIZE]),
373            _ => Err(self.default_dev_status()),
374        }
375    }
376    #[cfg(test)]
377    fn aes_decrypt_block(
378        &self,
379        _key_id: u16,
380        _key_block: u8,
381        _input: &[u8],
382    ) -> Result<[u8; ATCA_AES_DATA_SIZE], AtcaStatus> {
383        match self.dev_type {
384            AtcaDeviceType::AtcaTestDevSuccess => Ok([0x00; ATCA_AES_DATA_SIZE]),
385            _ => Err(self.default_dev_status()),
386        }
387    }
388    #[cfg(test)]
389    fn aes_ctr_init(
390        &self,
391        _slot_id: u8,
392        _counter_size: u8,
393        _iv: &[u8],
394    ) -> Result<atca_aes_ctr_ctx_t, AtcaStatus> {
395        match self.dev_type {
396            AtcaDeviceType::AtcaTestDevSuccess => {
397                let ctx: atca_aes_ctr_ctx_t = {
398                    let ctx = MaybeUninit::<atca_aes_ctr_ctx_t>::zeroed();
399                    unsafe { ctx.assume_init() }
400                };
401                Ok(ctx)
402            }
403            _ => Err(self.default_dev_status()),
404        }
405    }
406    #[cfg(test)]
407    fn aes_ctr_increment(&self, ctx: atca_aes_ctr_ctx_t) -> Result<atca_aes_ctr_ctx_t, AtcaStatus> {
408        match self.dev_type {
409            AtcaDeviceType::AtcaTestDevSuccess => Ok(ctx),
410            _ => Err(self.default_dev_status()),
411        }
412    }
413    /// Initialize context for AES CBC operation.
414    #[cfg(test)]
415    fn aes_cbc_init(&self, _slot_id: u8, _iv: &[u8]) -> Result<atca_aes_cbc_ctx_t, AtcaStatus> {
416        match self.dev_type {
417            AtcaDeviceType::AtcaTestDevSuccess => {
418                let ctx: atca_aes_cbc_ctx_t = {
419                    let ctx = MaybeUninit::<atca_aes_cbc_ctx_t>::zeroed();
420                    unsafe { ctx.assume_init() }
421                };
422                Ok(ctx)
423            }
424            _ => Err(self.default_dev_status()),
425        }
426    }
427    // A helper function that returns number of blocks and bytes of data
428    /// available for a given socket
429    #[cfg(test)]
430    fn get_slot_capacity(&self, _slot_id: u8) -> AtcaSlotCapacity {
431        let result: AtcaSlotCapacity = { Default::default() };
432        result
433    }
434}
435
436impl AteccDevice {
437    pub fn new(r_iface_cfg: AtcaIfaceCfg) -> Result<AteccDevice, String> {
438        let mut device = AteccDevice::default();
439        match r_iface_cfg.iface_type {
440            AtcaIfaceType::AtcaTestIface => (),
441            _ => {
442                let err = format!(
443                    "Software implementation of an AteccDevice does not support interface {}",
444                    r_iface_cfg.iface_type
445                );
446                return Err(err);
447            }
448        }
449        device.dev_type = match r_iface_cfg.devtype {
450            AtcaDeviceType::AtcaTestDevFail => AtcaDeviceType::AtcaTestDevFail,
451            AtcaDeviceType::AtcaTestDevSuccess => AtcaDeviceType::AtcaTestDevSuccess,
452            AtcaDeviceType::AtcaTestDevFailUnimplemented => {
453                AtcaDeviceType::AtcaTestDevFailUnimplemented
454            }
455            _ => {
456                let err = format!(
457                    "Software implementation of an AteccDevice does not support interface {}",
458                    r_iface_cfg.devtype
459                );
460                return Err(err);
461            }
462        };
463        Ok(device)
464    }
465    fn default_dev_status(&self) -> AtcaStatus {
466        match self.dev_type {
467            AtcaDeviceType::AtcaTestDevSuccess => AtcaStatus::AtcaSuccess,
468            _ => AtcaStatus::AtcaUnimplemented,
469        }
470    }
471}