A platform agnostic I2C driver for Microchip's crypto-authentication device i.e. ATECC608a, written entirely in Rust. This library implements APIs required to communicate with Microchip Security device - ATECC608a.
The ATECC608A device is a member of the Microchip CryptoAuthenticationâ„¢ family of crypto engine authentication devices with highly secure hardware-based key storage.
The ATECC608A device has a flexible command set that allows use in many applications, including the following: * Network/IoT Node Protection - Authenticates node IDs, ensures the integrity of messages, and supports key agreement to create session keys for message encryption. * Anti-Counterfeiting - Validates that a removable, replaceable, or consumable client is authentic. Examples of clients could be system accessories, electronic daughter cards, or other spare parts. It can also be used to validate a software/firmware module or memory storage element. * Protecting Firmware or Media - Validates code stored in flash memory at boot to prevent unauthorized modifications, encrypt downloaded program files as a common broadcast, or uniquely encrypt code images to be usable on a single system only. * Storing Secure Data - Stores secret keys for use by crypto accelerators in standard microprocessors. Programmable protection is available using encrypted/authenticated reads and writes. * Checking User Password - Validates user-entered passwords without letting the expected value become known, maps memorable passwords to a random number, and securely exchanges password values with remote systems.
The device includes an EEPROM array which can be used for storage of up to 16 keys, certificates, miscellaneous read/write, read-only or secret data, consumption logging, and security configurations. Access to the various sections of memory can be restricted in a variety of ways and then the configuration can be locked to prevent changes. Access to the device is made through a standard I2C Interface at speeds of up to 1 Mb/s(see Section I2C Interface). The interface is compatible with standard Serial EEPROM I2C interface specifications.
The ATECC608A is a command-based device which receives commands from the system, executes those commands, and then returns a result or error code. * Security Commands: This group of commands generally access the EEPROM space and/or perform cryptographic computation. * Cryptographic Commands: This subset of the security commands includes all the ECC commands which access the hardware ECC accelerator (GenKey, Sign, ECDH, and Verify) and the SHA commands which access the hardware SHA accelerator (CheckMac, DeriveKey, GenDig, HMAC, MAC, SHA, and Nonce).
heapless
and Postcard
for command packet construction.```Rust
// #![allow(warnings)]
extern crate nrf52840hal as hal; extern crate panichalt; extern crate nrf52840mdk; use cortexm_rt::{entry, exception};
use hal::gpio::{p0, p1}; use hal::target::Peripherals; use hal::timer::Timer; use hal::twim::{self, Twim}; // use cortexmsemihosting::hprintln; use RustyCryptoAuthLib::ATECC608A; use nrf52840mdk::Pins;
fn main() -> ! { let p = Peripherals::take().unwrap(); let pins = Pins::new(p0::Parts::new(p.P0), p1::Parts::new(p.P1)); let scl = pins.p27.intofloatinginput().degrade(); let sda = pins.p26.intofloatinginput().degrade();
let i2c_pins = twim::Pins { scl, sda };
let i2c = Twim::new(p.TWIM1, i2c_pins, twim::Frequency::K100);
let delay = Timer::new(p.TIMER0);
let timer = Timer::new(p.TIMER1);
let mut atecc608a = ATECC608A::new(i2c, delay, timer).unwrap();
// GENKEY COMMAND EXAMPLE
// Note: TFLXTLSConfig has slot 2 configured to hold an ECC private key.
// So, only GENKEY AND PRIVWRITE commands can be used to write (i.e. store or generate private keys) to this slot.
// Check `Slot access policies` section in my GitHub readme for more info.
let slot = 0x02;
let gen_public_key = match atecc608a.atcab_genkey(slot) { // public key retreived upon
Ok(v) => v, // generating and storing a new (random) ECC private key
Err(e) => panic!("Error generating ECC private key: {:?}", e), // in slot 2.
};
let comp_public_key = match atecc608a.atcab_get_pubkey(slot) { // public key computed from
Ok(v) => v, // the previously generated and stored
Err(e) => panic!("Error retrieving ECC public key: {:?}", e), // private key in slot 2.
};
assert_eq!(&gen_public_key[..], &comp_public_key[..]);
loop {}
}
fn HardFault(ef: &cortexmrt::ExceptionFrame) -> ! { panic!("HardFault at {:#?}", ef); }
fn DefaultHandler(irqn: i16) { panic!("Unhandled exception (IRQn = {})", irqn); }
``` Please see the examples folder for more.
The ATECC608A is a command-based device which receives commands from the system, executes those commands, and then returns a result or error code. It contains an integrated EEPROM storage memory and SRAM buffer. The EEPROM memory contains a total of 1400 bytes and is divided into the following zones:
Before we begin, we'll need to program the Config zone with values that will determine the access policy for how each data slot will respond. The configuration zone can be modified until it has been locked (LockConfig set to !=0x55). In order to enable the access policies, the LockValue byte must be set. Here's a comparison between an out-of-the-box config Vs sample (ATECC-TFLXTLS) config. (Sample config taken from Microchip. It's used in some of its pre-provisioned variants.)
Writing the ATECC-TFLXTLS configuration to the device will yield a personalised device i.e. you can now generate/store keys, certificates and other content in the device's EEPROM slots as shown in the table below. For a more detailed view of slot access policies and commands that can be used on each slot - Detailed slot access policies
| Slot | Use-case | |-------|-----------------------------------| | 0 | Primary private key | | 1 | Internal sign private key | | 2 | Secondary private key 1 | | 3 | Secondary private key 2 | | 4 | Secondary private key 3 | | 5 | Secret key | | 6 | IO protection key | | 7 | Secure boot digest | | 8 | General data | | 9 | AES key | | 10 | Device compressed certificate | | 11 | Signer public key | | 12 | Signer compressed certificate | | 13 | Parent public key or general data | | 14 | Validated public key | | 15 | Secure boot public key |
Important: Please do not proceed before reading this section
1. To write the ATECC-TFLXTLS configuration bytes to the device, use the example atcab_write_config_zone.rs
included in the examples folder.
2. Use the read command example - atcab_read_config_zone.rs
to read contents (i.e. all 128 bytes) of config zone. This is just a double check to see if the correct set of bytes (i.e. ATECC-TFLXTLS config bytes) were written to the device.
3. Before we can begin populating (i.e. read from or write to) data or OTP zones, we have to lock the config zone. Use the atcab_lock_config_zone_crc.rs
example to lock the config zone. Note: locking the config zone is an irreversible operation. So, please make sure you get everything right before you do.
3. Once that's done, you can start populating the device's data zone with private ECC keys or externally generated public keys of your choice as per the above table.
- The example atcab_sign_and_verify.rs
does just that. It generates and loads a new (random) ECC private key into slot 3 of the device. The private key is generated 'within-the-device' and never leaves it. The example contains a test message, which is signed by the private key and verified by the corresponding 'computed' public key.
- Note: In step 3, you can do this for all private keys slots (0-4) as not all access policies are strictly enforced. For example, private keys in sot 0-1 are permanent and slot2-4 are updateable as per policy. But because the data zone is unlocked, commands like WRITE or GENKEY
will still work without restrictions, even though a slot is configured to be (permanently) not writable.
- In other words, this is step where you actually populate all slots on the device with the keys, certificates and other data and when you're happy with the contents in the data zone, move to step 4.
4. Only after locking the data zone (i.e. byte [86] or LockValue
of the config zone) are access policies for slots strictly enforced. For example: you can no longer issue the GENKEY command to generate a new random private for slots 0 and 1 but you can issue GENKEY to compute the public key of the corresponding permanent private keys in slots 0 and 1.
- Note: I'm yet to implement a method to lock the data zone. I will be adding more commands that will need testing. If you need it, drop a note.
(1) Not all features are implemented, see follow list for details
For questions, issues, feature requests, and other changes, please file an issue in the github project.
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.