From b5e1764acfd28b5cc8e1be46a3a4bbbf51720bb0 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 26 Sep 2023 15:26:30 +1000 Subject: [PATCH] boards: apollo3: Initial support for the Atecc508a CryptoAuthentication Device Signed-off-by: Alistair Francis --- boards/apollo3/lora_things_plus/Cargo.toml | 9 ++ boards/apollo3/lora_things_plus/src/main.rs | 119 ++++++++++++++++-- .../lora_things_plus/src/tests/atecc508a.rs | 86 +++++++++++++ .../lora_things_plus/src/tests/csrng.rs | 33 +++++ .../apollo3/lora_things_plus/src/tests/mod.rs | 5 + 5 files changed, 241 insertions(+), 11 deletions(-) create mode 100644 boards/apollo3/lora_things_plus/src/tests/atecc508a.rs create mode 100644 boards/apollo3/lora_things_plus/src/tests/csrng.rs diff --git a/boards/apollo3/lora_things_plus/Cargo.toml b/boards/apollo3/lora_things_plus/Cargo.toml index 72a9d54d56c..f40997dc694 100644 --- a/boards/apollo3/lora_things_plus/Cargo.toml +++ b/boards/apollo3/lora_things_plus/Cargo.toml @@ -19,3 +19,12 @@ apollo3 = { path = "../../../chips/apollo3" } capsules-core = { path = "../../../capsules/core" } capsules-extra = { path = "../../../capsules/extra" } capsules-system = { path = "../../../capsules/system" } + +[features] +default = [] + +# This feature enables support for the ATECC508A Cryptographic Co-Processor +# Breakout. If you connect one of these +# (https://www.sparkfun.com/products/15573) via the I2C Qwiic connector you +# should enable this feature. +atecc508a = [] diff --git a/boards/apollo3/lora_things_plus/src/main.rs b/boards/apollo3/lora_things_plus/src/main.rs index a3b80e2e331..eb397d28d10 100644 --- a/boards/apollo3/lora_things_plus/src/main.rs +++ b/boards/apollo3/lora_things_plus/src/main.rs @@ -14,7 +14,7 @@ //! and //! for details on the pin break outs //! -//! ION0: Qwiic I2C +//! IOM0: Qwiic I2C //! IOM1: Not connected //! IOM2: Broken out SPI //! IOM3: Semtech SX1262 @@ -57,6 +57,15 @@ use kernel::platform::{KernelResources, SyscallDriverLookup}; use kernel::scheduler::round_robin::RoundRobinSched; use kernel::{create_capability, debug, static_init}; +#[cfg(feature = "atecc508a")] +use { + capsules_core::virtualizers::virtual_i2c::MuxI2C, + components::atecc508a::Atecc508aComponent, + kernel::hil::entropy::Entropy32, + kernel::hil::gpio::{Configure, Output}, + kernel::hil::rng::Rng, +}; + /// Support routines for debugging I/O. pub mod io; @@ -80,7 +89,6 @@ const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy = capsules_system::process_policies::PanicFaultPolicy {}; // Test access to the peripherals -#[cfg(test)] static mut PERIPHERALS: Option<&'static Apollo3DefaultPeripherals> = None; // Test access to board #[cfg(test)] @@ -101,6 +109,8 @@ static mut BME280: Option< >, > = None; static mut CCS811: Option<&'static capsules_extra::ccs811::Ccs811<'static>> = None; +#[cfg(feature = "atecc508a")] +static mut ATECC508A: Option<&'static capsules_extra::atecc508a::Atecc508a<'static>> = None; /// Dummy buffer that causes the linker to reserve enough space for the stack. #[no_mangle] @@ -155,10 +165,80 @@ struct LoRaThingsPlus { temperature: &'static TemperatureDriver, humidity: &'static HumidityDriver, air_quality: &'static capsules_extra::air_quality::AirQualitySensor<'static>, + rng: Option< + &'static capsules_core::rng::RngDriver< + 'static, + capsules_core::rng::Entropy32ToRandom< + 'static, + capsules_extra::atecc508a::Atecc508a<'static>, + >, + >, + >, scheduler: &'static RoundRobinSched<'static>, systick: cortexm4::systick::SysTick, } +#[cfg(feature = "atecc508a")] +fn atecc508a_wakeup() { + let peripherals = unsafe { PERIPHERALS.unwrap() }; + + peripherals.gpio_port[6].make_output(); + peripherals.gpio_port[6].clear(); + + // The ATECC508A requires the SDA line to be low for at least 60us + // to wake up. + for _i in 0..700 { + cortexm4::support::nop(); + } + + // Enable SDA and SCL for I2C (exposed via Qwiic) + let _ = &peripherals + .gpio_port + .enable_i2c(&peripherals.gpio_port[6], &peripherals.gpio_port[5]); +} + +#[cfg(feature = "atecc508a")] +unsafe fn setup_atecc508a( + board_kernel: &'static kernel::Kernel, + memory_allocation_cap: &dyn capabilities::MemoryAllocationCapability, + mux_i2c: &'static MuxI2C<'static, apollo3::iom::Iom<'static>>, +) -> &'static capsules_core::rng::RngDriver< + 'static, + capsules_core::rng::Entropy32ToRandom<'static, capsules_extra::atecc508a::Atecc508a<'static>>, +> { + let atecc508a = Atecc508aComponent::new(mux_i2c, 0x60, atecc508a_wakeup).finalize( + components::atecc508a_component_static!(apollo3::iom::Iom<'static>), + ); + ATECC508A = Some(atecc508a); + + // Convert hardware RNG to the Random interface. + let entropy_to_random = static_init!( + capsules_core::rng::Entropy32ToRandom< + 'static, + capsules_extra::atecc508a::Atecc508a<'static>, + >, + capsules_core::rng::Entropy32ToRandom::new(atecc508a) + ); + atecc508a.set_client(entropy_to_random); + // Setup RNG for userspace + let rng_local = static_init!( + capsules_core::rng::RngDriver< + 'static, + capsules_core::rng::Entropy32ToRandom< + 'static, + capsules_extra::atecc508a::Atecc508a<'static>, + >, + >, + capsules_core::rng::RngDriver::new( + entropy_to_random, + board_kernel.create_grant(capsules_core::rng::DRIVER_NUM, memory_allocation_cap) + ) + ); + entropy_to_random.set_client(rng_local); + + rng_local +} + /// Mapping of integer syscalls to objects that implement syscalls. impl SyscallDriverLookup for LoRaThingsPlus { fn with_driver(&self, driver_num: usize, f: F) -> R @@ -178,6 +258,13 @@ impl SyscallDriverLookup for LoRaThingsPlus { capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)), capsules_extra::humidity::DRIVER_NUM => f(Some(self.humidity)), capsules_extra::air_quality::DRIVER_NUM => f(Some(self.air_quality)), + capsules_core::rng::DRIVER_NUM => { + if let Some(rng) = self.rng { + f(Some(rng)) + } else { + f(None) + } + } _ => f(None), } } @@ -222,9 +309,9 @@ unsafe fn setup() -> ( &'static kernel::Kernel, &'static LoRaThingsPlus, &'static apollo3::chip::Apollo3, - &'static Apollo3DefaultPeripherals, ) { let peripherals = static_init!(Apollo3DefaultPeripherals, Apollo3DefaultPeripherals::new()); + PERIPHERALS = Some(peripherals); // No need to statically allocate mcu/pwr/clk_ctrl because they are only used in main! let mcu_ctrl = apollo3::mcuctrl::McuCtrl::new(); @@ -249,10 +336,6 @@ unsafe fn setup() -> ( peripherals .gpio_port .enable_uart(&peripherals.gpio_port[48], &peripherals.gpio_port[49]); - // Enable SDA and SCL for I2C (exposed via Qwiic) - peripherals - .gpio_port - .enable_i2c(&peripherals.gpio_port[6], &peripherals.gpio_port[5]); // Enable Main SPI peripherals.gpio_port.enable_spi( &peripherals.gpio_port[27], @@ -327,6 +410,11 @@ unsafe fn setup() -> ( .finalize(components::process_printer_text_component_static!()); PROCESS_PRINTER = Some(process_printer); + // Enable SDA and SCL for I2C (exposed via Qwiic) + peripherals + .gpio_port + .enable_i2c(&peripherals.gpio_port[6], &peripherals.gpio_port[5]); + // Init the I2C device attached via Qwiic let i2c_master_buffer = static_init!( [u8; capsules_core::i2c_master::BUFFER_LENGTH], @@ -379,6 +467,15 @@ unsafe fn setup() -> ( .finalize(components::air_quality_component_static!()); CCS811 = Some(ccs811); + #[cfg(feature = "atecc508a")] + let rng = Some(setup_atecc508a( + board_kernel, + &memory_allocation_cap, + mux_i2c, + )); + #[cfg(not(feature = "atecc508a"))] + let rng = None; + // Init the broken out SPI controller let external_mux_spi = components::spi::SpiMuxComponent::new(&peripherals.iom2).finalize( components::spi_mux_component_static!(apollo3::iom::Iom<'static>), @@ -483,6 +580,7 @@ unsafe fn setup() -> ( temperature, humidity, air_quality, + rng, scheduler, systick, } @@ -514,7 +612,7 @@ unsafe fn setup() -> ( debug!("{:?}", err); }); - (board_kernel, artemis_nano, chip, peripherals) + (board_kernel, artemis_nano, chip) } /// Main function. @@ -530,7 +628,7 @@ pub unsafe fn main() { #[cfg(not(test))] { - let (board_kernel, sf_lora_thing_plus_board, chip, _peripherals) = setup(); + let (board_kernel, sf_lora_thing_plus_board, chip) = setup(); let main_loop_cap = create_capability!(capabilities::MainLoopCapability); @@ -549,11 +647,10 @@ use kernel::platform::watchdog::WatchDog; #[cfg(test)] fn test_runner(tests: &[&dyn Fn()]) { unsafe { - let (board_kernel, sf_lora_thing_plus_board, _chip, peripherals) = setup(); + let (board_kernel, sf_lora_thing_plus_board, _chip) = setup(); BOARD = Some(board_kernel); PLATFORM = Some(&sf_lora_thing_plus_board); - PERIPHERALS = Some(peripherals); MAIN_CAP = Some(&create_capability!(capabilities::MainLoopCapability)); PLATFORM.map(|p| { diff --git a/boards/apollo3/lora_things_plus/src/tests/atecc508a.rs b/boards/apollo3/lora_things_plus/src/tests/atecc508a.rs new file mode 100644 index 00000000000..686521bb61c --- /dev/null +++ b/boards/apollo3/lora_things_plus/src/tests/atecc508a.rs @@ -0,0 +1,86 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2023. + +//! Test that the Atecc508a works + +use crate::tests::run_kernel_op; +use crate::ATECC508A; +use kernel::debug; + +#[test_case] +fn read_config() { + run_kernel_op(100_000); + + debug!("check run ATECC508A config... "); + run_kernel_op(100); + + unsafe { + let atecc508a = ATECC508A.unwrap(); + + atecc508a.read_config_zone().unwrap(); + } + + run_kernel_op(150_000); + debug!(" [ok]"); + run_kernel_op(100); +} + +#[test_case] +fn setup_and_lock_tock_config() { + run_kernel_op(100_000); + + debug!("Lock the Tock config..."); + run_kernel_op(100); + + unsafe { + let atecc508a = ATECC508A.unwrap(); + + atecc508a.read_config_zone().unwrap(); + run_kernel_op(150_000); + + if atecc508a.device_locked() { + debug!(" [ok] - Already locked"); + return; + } + + debug!("This can not be undone!"); + run_kernel_op(100); + debug!("Power off the board now to stop the process!"); + run_kernel_op(100); + + // Provide a chance for the user to stop the process + run_kernel_op(1_000_000); + + debug!("Setting up config"); + atecc508a.setup_tock_config().unwrap(); + run_kernel_op(150_000); + + debug!("Locking zone config"); + atecc508a.lock_zone_config().unwrap(); + run_kernel_op(200_000); + + debug!("Generating public key"); + atecc508a.create_key_pair(0).unwrap(); + run_kernel_op(300_000); + + let public_key = atecc508a.get_public_key(0).unwrap(); + debug!("public_key: {:x?}", public_key.get()); + + debug!("Locking data and OTP"); + atecc508a.lock_data_and_otp().unwrap(); + run_kernel_op(300_000); + + debug!("Locking slot 0"); + atecc508a.lock_slot0().unwrap(); + run_kernel_op(300_000); + + debug!("Reading new config"); + atecc508a.read_config_zone().unwrap(); + run_kernel_op(100_000); + } + + run_kernel_op(100_000); + debug!(" [ok]"); + run_kernel_op(100); +} diff --git a/boards/apollo3/lora_things_plus/src/tests/csrng.rs b/boards/apollo3/lora_things_plus/src/tests/csrng.rs new file mode 100644 index 00000000000..2e1a490fda5 --- /dev/null +++ b/boards/apollo3/lora_things_plus/src/tests/csrng.rs @@ -0,0 +1,33 @@ +// Licensed under the Apache License, Version 2.0 or the MIT License. +// SPDX-License-Identifier: Apache-2.0 OR MIT +// Copyright Tock Contributors 2022. + +//! Test that the RNG works + +use crate::tests::run_kernel_op; +use crate::ATECC508A; +use capsules_core::test::rng::TestEntropy32; +use kernel::debug; +use kernel::hil::entropy::Entropy32; +use kernel::static_init; + +#[test_case] +fn run_csrng_entropy32() { + // We need to make sure the device is setup + run_kernel_op(10_000); + + debug!("check run CSRNG Entropy 32... "); + run_kernel_op(100); + + unsafe { + let rng = ATECC508A.unwrap(); + + let t = static_init!(TestEntropy32<'static>, TestEntropy32::new(rng)); + rng.set_client(t); + + t.run(); + } + run_kernel_op(10_000); + debug!(" [ok]"); + run_kernel_op(100); +} diff --git a/boards/apollo3/lora_things_plus/src/tests/mod.rs b/boards/apollo3/lora_things_plus/src/tests/mod.rs index 3e815074963..0a616c943b8 100644 --- a/boards/apollo3/lora_things_plus/src/tests/mod.rs +++ b/boards/apollo3/lora_things_plus/src/tests/mod.rs @@ -34,6 +34,11 @@ fn trivial_assertion() { run_kernel_op(10000); } +#[cfg(feature = "atecc508a")] +mod atecc508a; +#[cfg(feature = "atecc508a")] +mod csrng; + mod environmental_sensors; mod multi_alarm; mod spi_controller;