diff --git a/README.md b/README.md index 5ffa792..698bead 100644 --- a/README.md +++ b/README.md @@ -1,274 +1,62 @@ -# eCTF Insecure Example -This repository holds the insecure example design for an eCTF MISC system. - - -## Layout - -- `application_processor` - Code for the application processor - - `project.mk` - This file defines project specific variables included in the Makefile - - `Makefile` - This makefile is invoked by the eCTF tools when creating a application processor - - `inc` - Directory with c header files - - `src` - Directory with c source files - - `wolfssl` - Location to place wolfssl library for included Crypto Example -- `deployment` - Code for deployment secret generation - - `Makefile` - This makefile is invoked by the eCTF tools when creating a deployment - - You may put other scripts here to invoke from the Makefile -- `ectf_tools` - Host tools and build tools - DO NOT MODIFY ANYTHING IN THIS DIRECTORY - - `attestation_tool.py` - Runs attestation command on application processor - - `boot_tool.py` - Boots the application processor and sensors - - `list_tool.py` - Lists what sensors are currently online - - `replace_tool.py` - Replaces a sensor id on the application processor - - `build tools` - Tools to build -- `component` - Code for the components - - `project.mk` - This file defines project specific variables included in the Makefile - - `Makefile` - This makefile is invoked by the eCTF tools when creating a component - - `inc` - Directory with c header files - - `src` - Directory with c source files - - `wolfssl` - Location to place wolfssl library for included Crypto Example -- `shell.nix` - Nix configuration file for Nix environment -- `custom_nix_pkgs` - Custom derived nix packages - - `analog-openocd.nix` - Custom nix package to build Analog Devices fork of OpenOCD - - -## Usage and Requirements - -This repository contains two main elements: firmware source code and tooling. - -Firmware is built through the included eCTF Tools. These tools invoke the Makefiles -in specific ways in the provided Nix environment. Firmware compiling should be executed -through these included tools. - -Source code and tooling is provided that runs directly on the host. All of these tools are -created in Python. The tools can be easily installed with the use of Poetry. Once inside -of the activated Nix environment, run `poetry install` to initialize the Poetry environment. -These tools can be invoked either through `poetry run {toolname}` or by activating the poetry environment -with `poetry shell` and then running as standard python programs. - -### Environment Build - -The environment is built with a Nix, which should install all packages -necessary for running the design in a reproducible fashion. The environment is automatically -built when an eCTF Build Tool is run. If building `analog_openocd.nix` this step may -take some time to complete. - -Development can be prototyped by launching into the Nix environment through `nix-shell`. - -### Host Tools - -Host Tools for the 2024 competition do not need to be modified by teams at any point. Your design -should work with the standardized interface between host and MISC system. The host tools will -pass any required arguments to the MISC system and receive all relevant output. - -### Deployment - -When creating a deployment, the Makefile within the `deployment` folder of the design -repo will be executed. This is the only stage in which information can be shared between -separate portions of the build (e.g. components and application processors). A clean -target should be implemented in this Makefile to allow for elimination of all generated secrets. - -### Application Processor and Component - -When building the application processor and components, the `Makefile` with the -respective directories will be invoked. The eCTF Tools will populate parameters into -a C header file `ectf_params.h` within the design directory. Examples of these header -files can be found in the respective main source files for the application processor -and component. - -## Using the eCTF Tools -### Building the deployment -This will run the `Makefile` found in the deployment folder using the following inputs: - -``` -ectf_build_depl --help -usage: eCTF Build Deployment Tool [-h] -d DESIGN - -Build a deployment using Nix - -options: - -h, --help show this help message and exit - -d DESIGN, --design DESIGN - Path to the root directory of the included design -``` - -**Example Utilization** -```bash -ectf_build_depl -d ../ectf-2024-example -``` -### Building the Application Processor -This will run the `Makefile` found in the application processor folder using the following inputs: - -``` -ectf_build_ap --help -usage: eCTF Build Application Processor Tool [-h] -d DESIGN -on OUTPUT_NAME [-od OUTPUT_DIR] -p P - -b BOOT_MESSAGE - -Build an Application Processor using Nix - -options: - -h, --help show this help message and exit - -d DESIGN, --design DESIGN - Path to the root directory of the included design - -on OUTPUT_NAME, --output-name OUTPUT_NAME - Output prefix of the built application processor binary Example 'ap' -> a - -od OUTPUT_DIR, --output-dir OUTPUT_DIR - Output name of the directory to store the result: default: . - -p PIN, --pin PIN PIN for built application processor - -t TOKEN, --token TOKEN - Token for built application processor - -c COMPONENT_CNT, --component-cnt COMPONENT_CNT - Number of components to provision Application Processor for - -ids COMPONENT_IDS, --component-ids COMPONENT_IDS - Component IDs to provision the Application Processor for - -b BOOT_MESSAGE, --boot-message BOOT_MESSAGE - Application Processor boot message -``` - -**Example Utilization** -```bash -ectf_build_ap -d ../ectf-2024-example -on ap --p 123456 -c 2 -ids "0x11111124, 0x11111125" -b "Test boot message" -t 0123456789abcdef -od build -``` - -### Building the Component -``` -ectf_build_comp --help -usage: eCTF Build Application Processor Tool [-h] -d DESIGN -on OUTPUT_NAME [-od OUTPUT_DIR] -id COMPONENT_ID -b BOOT_MESSAGE -al - ATTESTATION_LOCATION -ad ATTESTATION_DATE -ac ATTESTATION_CUSTOMER - -Build an Application Processor using Nix - -options: - -h, --help show this help message and exit - -d DESIGN, --design DESIGN - Path to the root directory of the included design - -on OUTPUT_NAME, --output-name OUTPUT_NAME - Output prefix of the built application processor binary Example 'ap' -> ap.bin, ap.elf, ap.img - -od OUTPUT_DIR, --output-dir OUTPUT_DIR - Output name of the directory to store the result: default: . - -id COMPONENT_ID, --component-id COMPONENT_ID - Component ID for the provisioned component - -b BOOT_MESSAGE, --boot-message BOOT_MESSAGE - Component boot message - -al ATTESTATION_LOCATION, --attestation-location ATTESTATION_LOCATION - Attestation data location field - -ad ATTESTATION_DATE, --attestation-date ATTESTATION_DATE - Attestation data date field - -ac ATTESTATION_CUSTOMER, --attestation-customer ATTESTATION_CUSTOMER - Attestation data customer field -``` - -**Example Utilization** -```bash -ectf_build_comp -d ../ectf-2024-example -on comp -od build -id 0x11111125 -b "Component boot" -al "McLean" -ad "08/08/08" -ac "Fritz" -``` - -## Flashing -Flashing the MAX78000 is done through the eCTF Bootloader. You will need to initially flash the eCTF Bootloader onto the provided hardware. -This can be done easily by dragging and dropping the [provided bootloader](https://ectfmitre.gitlab.io/ectf-website/2024/components/bootloader.html) (for design phase:`insecure.bin`) to the DAPLink interface. DAPLink will show up as an external drive when connected to your system. Succesfull installation would make a blue LED flash on the board. - -To flash a specific bootloader image on the board (AP or Components), use `ectf_update`. -``` -ectf_update [-h] --infile INFILE --port PORT - -optional arguments: - -h, --help show this help message and exit - --infile INFILE Path to the input binary - --port PORT Serial port -``` - -**Example Utilization** -```bash -ectf_update --infile example_fw/build/firmware.img --port /dev/ttyUSB0 -``` - -## Host Tools -### List Tool -The list tool applies the required list components functionality from the MISC system. This is availble on the -PATH within the Poetry environment as `ectf_list`. - -``` -ectf_list -h -usage: eCTF List Host Tool [-h] -a APPLICATION_PROCESSOR - -List the components connected to the medical device - -options: - -h, --help show this help message and exit - -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR - Serial device of the AP -``` - -**Example Utilization** -``` bash -ectf_list -a /dev/ttyUSB0 -``` - -### Boot Tool -The boot tool boots the full system. This is available on the PATH within the Poetry environment as `ectf_boot` - -``` -ectf_boot --help -usage: eCTF Boot Host Tool [-h] -a APPLICATION_PROCESSOR - -Boot the medical device - -options: - -h, --help show this help message and exit - -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR - Serial device of the AP -``` - -**Example Utilization** -``` bash -ectf_boot -a /dev/ttyUSB0 -``` - -### Replace Tool -The replace tool replaces a provisioned component on the system with a new component. -This is available on the PATH within the Poetry environment as `ectf_replace`. - -``` -ectf_replace --help -usage: eCTF Replace Host Tool [-h] -a APPLICATION_PROCESSOR -t TOKEN -i COMPONENT_IN -o COMPONENT_OUT - -Replace a component on the medical device - -options: - -h, --help show this help message and exit - -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR - Serial device of the AP - -t TOKEN, --token TOKEN - Replacement token for the AP - -i COMPONENT_IN, --component-in COMPONENT_IN - Component ID of the new component - -o COMPONENT_OUT, --component-out COMPONENT_OUT - Component ID of the component being replaced -``` - -**Example Utilization** -``` bash -ectf_replace -a /dev/ttyUSB0 -t 0123456789abcdef -i 0x11111126 -o 0x11111125 -``` - -### Attestation Tool -The attestation tool returns the confidential attestation data provisioned on a component. -This is available on the PATH within the Poetry environment as `ectf_attestation`. - -``` -ectf_attestation --help -usage: eCTF Attestation Host Tool [-h] -a APPLICATION_PROCESSOR -p PIN -c COMPONENT - -Return the attestation data from a component - -options: - -h, --help show this help message and exit - -a APPLICATION_PROCESSOR, --application-processor APPLICATION_PROCESSOR - Serial device of the AP - -p PIN, --pin PIN PIN for the AP - -c COMPONENT, --component COMPONENT - Component ID of the target component -``` - -**Example Utilization** -``` -ectf_attestation -a /dev/ttyUSB0 -p 123456 -c 0x11111124 -``` +# UIUC MISC Design for MITRE eCTF 2024 + +This repository contain's the University of Illinois Urbana-Champaign's design for the MITRE eCTF 2024 competition (embedded CTF). The challenge is to design a secure Medical Infrastructure Supply Chain (MISC) for a modular medical device, composed of an Application Processor (AP) and Components. + +Our design expands upon the required functionality by implementing the following key security features: + +- 🔐 **Secure Communication with our HIDE Protocol** + - Our challenge-response protocol prevents the replay of messages and allows for attested communication between the AP and Components. + - Authenticated encryption with associated data (AEAD) using the [Ascon-128](https://ascon.iaik.tugraz.at/) cipher ensures the confidentiality and integrity of messages. + - All communications between the AP and Components use HIDE. +- 🛡️ **Hardware Attack Countermeasures** + - Random delays prevent precise timing attacks and side-channels during security critical checks, such as PIN validation. + - Repetition of critical operations mitigate fault-injection attacks. +- 🦀 **Written entirely in Rust!*** + - Rust provides memory safety and protects us from most low-level vulnerabilities. + - Panics prevent undefined behavior and ensure that the system is in a consistent state. Panics are indicated by a flashing red LED on the boards. + - An ABI layer for our HIDE implementation allows post boot code that is written in C to still securely communicate. + +\* *This statement is approved by the White House.* + +## Repository Structure + +- `application_processor`: The firmware for the Application Processor. + - `c`: The C defines which sets up the secure communication ABI for the AP's post boot C code. + - `rust`: The Rust firmware code specific to the AP. +- `component`: The firmware for an individual Component. + - `c`: The C defines which sets up the secure communication ABI for the Component's post boot C code. + - `rust`: The Rust firmware code specific to the Component. +- `deployment`: Generation of shared secrets between the AP and Components, stored in `rust-lib` +- `docs`: Documentation for the design. +- `rust-lib`: Shared Rust code between the AP and Components. + - `ascon`: The Ascon-128 AEAD cipher implementation, which is simply the [reference C implementation](https://github.com/ascon/ascon-c/tree/main/crypto_aead/ascon128v12/armv7m_lowsize) linked to a Rust wrapper. + - `ectf-board`: Provides a board abstraction of the [MAX78000FTHR](https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/max78000fthr.html) and shares functions between the AP and the Component. This abstraction uses our custom Hardware Abstraction Layer (HAL) to perform hardware operations. Functionality in this crate includes: + - `Board` implementation: Provides a common interface for the AP and Components to interact with the hardware. + - `secure_comms`: Implements the HIDE communication layer. + - `ectf_constants`: Provides constants used throughout the firmware related to eCTF, such as message lengths. + - `ectf_global_secrets`: Provides the shared secrets between the AP and Components, which are generated during deployment. + - `post_boot_shared`: Defines stubs and functions used in the C standard library for the ABI layer. + - `hal`: Our custom Hardware Abstraction Layer (HAL) for the MAX78000FTHR. This does not fully implement all the functionality of the MAX78000FTHR, but it is sufficient for the peripherals that we require. Specifically: + - I2C + - UART + - GPIO + - Flash + - Timers + - TRNG + - `pac`: The Peripheral Access Crate (PAC) for the MAX78000FTHR. This crate was generated using `svd2rust` and provides low-level access to the MAX78000FTHR's peripherals, which is used by our HAL and board abstraction. + +## Documentation + +We provide our design document in the `docs` directory in both markdown and PDF format. We love Mermaid sequence diagrams and those are provided as well. Here is a quick link: + +- [UIUC Design Document](docs/2024_eCTF_UIUC_Design_Document.pdf) + +The code itself is also heavily documented using Rust doc comments. In any directory where a Rust crate is located, you can generate HTML documentation using the following command: + +```sh +cargo doc --open +``` + +## License + +This project is licensed under the Apache License, Version 2.0 - see the [LICENSE](LICENSE.txt) file for details. \ No newline at end of file diff --git a/application_processor/rust/src/main.rs b/application_processor/rust/src/main.rs index 4af4e0e..a063fd8 100644 --- a/application_processor/rust/src/main.rs +++ b/application_processor/rust/src/main.rs @@ -9,6 +9,7 @@ use ectf_board::{ secure_comms as hide, ectf_constants::{*}, }; +use once_cell::sync::Lazy; mod ectf_ap_params; use ectf_ap_params::{*}; @@ -16,10 +17,11 @@ use ectf_ap_params::{*}; mod post_boot; mod flash; +pub static BOARD: Lazy = Lazy::new(|| Board::new(RNG_SEED)); #[entry] fn main() -> ! { - let board = Board::new(); + let board = &BOARD; i2c1::master_config(&board.i2c1); board.send_host_debug(b"AP initialized!"); @@ -44,20 +46,6 @@ fn main() -> ! { board.send_host_debug(b"Booting..."); boot_verify(&board); } - // TODO: Remove - // Ok("test") => { - // use tests::{*}; - // test_hide(&board, false); - // test_ascon(&board); - // test_random(&board); - // test_flash(&board); - // test_timer(&board); - // loop { - // board.delay_timer_wait_random_us(1_000_000, 5_000_000); - // board.send_host_debug(b"Hello, world!"); - // board.led_toggle(Led::Green); - // } - // } _ => { board.send_host_debug(b"Unknown command"); } @@ -170,8 +158,8 @@ fn attest_component(board: &Board) { board.delay_timer_wait_random_us(100, 100_000); let is_correct3 = &result.as_slice() == &AP_PIN_HASH_3; - // Wait until 1.5 seconds total - board.transaction_timer_wait_until_us(1_500_000); + // Wait until 2.5 seconds total + board.transaction_timer_wait_until_us(2_500_000); // If all three hashes are correct, send the attestation data board.delay_timer_wait_random_us(100, 10_000); diff --git a/attest_guide.md b/attest_guide.md deleted file mode 100644 index d421054..0000000 --- a/attest_guide.md +++ /dev/null @@ -1,246 +0,0 @@ -# :runner: Attest Subteam Survival Guide - -Hi, I'm Emma, and welcome to the attest subteam :tada:! I want to set you up for success as much as I can, so here is a guide that hopefully will help you do so. This document is a perpetual work in progress so feel free to recommend additional resources and sections. - -## Table of Contents - -I wasn't expecting to have so much to say, but I think everything here is important enough to keep around. Here's a table of contents to help you navigate. - -- [Important Links](#important-links) -- [Functional Stuff](#functional-stuff) - - [Attestation](#attestation) - - [Replace Component](#replace-component) - - [List Components](#list-components) - - [Security Requirements](#security-requirements) -- [Development Stuff](#development-stuff) - - [Documentation](#documentation) - - [Rust (and Systems Programming Generally)](#rust) - - [Nix](#nix) - - [Embedded Systems](#embed) -- [Security Stuff](#security-stuff) - - [CIA Triad](#cia) - - [Timing Attacks (and Side Channels Generally)](#timing) - - [Hashing and Argon2](#hash) - - [Salting](#salt) - -## Important Links - -I hate hunting down links as much as you probably do, so here's the important ones. - -- [GitHub issues](https://github.com/sigpwny/2024-ectf-uiuc/issues) -- [Project tracker](https://github.com/orgs/sigpwny/projects/3) -- [Full eCTF guide/rulebook](https://ectfmitre.gitlab.io/ectf-website/2024/index.html) - - [System architecture](https://ectfmitre.gitlab.io/ectf-website/2024/specs/system_architecture.html) - - [Functional requirements](https://ectfmitre.gitlab.io/ectf-website/2024/specs/functional_reqs.html) - - [Detailed specs](https://ectfmitre.gitlab.io/ectf-website/2024/specs/detailed_specs.html) - - [Security requirements](https://ectfmitre.gitlab.io/ectf-website/2024/specs/security_reqs.html) - - [Attack flags](https://ectfmitre.gitlab.io/ectf-website/2024/flags/attack_flags.html) -- [Insecure example code](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example) - - [Application processor](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/application_processor/src/application_processor.c) - - [Component](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/application_processor/src/component.c) - -## Functional Stuff - -There are four pre-boot functional elements that we as a larger team need to support for the board. The attestation subteam will be in charge of three of those commands (because we're just that cool :sunglasses:). Each element has timing requirements and message output requirements we need to adhere to. - -### Attestation - -- [High-level description](https://ectfmitre.gitlab.io/ectf-website/2024/specs/functional_reqs.html#attest) -- [Detailed description](https://ectfmitre.gitlab.io/ectf-website/2024/specs/detailed_specs.html#attestation) -- Insecure Example - - [application_processor.c lines 300-323](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/application_processor/src/application_processor.c#L300) - - [application_processor.c lines 386-395](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/application_processor/src/application_processor.c#L386) - - [applicaton_processor.c lines 474-486](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/application_processor/src/application_processor.c#L474) - - [component.c lines 198-203](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/component/src/component.c#L198) - -We need to be able to... - -- Print all fields of a component's attestation data -- Only print the attestation data if the Attestation PIN is valid - -Functionally, we need to provide these outputs: - -|Level|Message format|Example| -|-----|--------------|-------| -|Info| `C>{Component ID prefixed by 0x}\n` |`C>0x02\n` | -|Info| `LOC>{Attestation location}\n` | `LOC>Boston\n` | -|Info| `DATE>{Attestation date}\n` | `DATE>01/01/1970\n` | -|Info| `CUST>{Attestation customer}\n` | `CUST>MITRE\n` | -|Success| `Attest\n` | `Attest\n`| -|Error| Any error message | `Attest failed\n` | - - -### Replace Component - -- [High-level description](https://ectfmitre.gitlab.io/ectf-website/2024/specs/functional_reqs.html#replace) -- [Detailed description](https://ectfmitre.gitlab.io/ectf-website/2024/specs/detailed_specs.html#replace-component) -- Insecure example - - [application_processor.c lines 398-407](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/component/src/appliction_processor.c#L398) - - [application_processor.c lines 437-471](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/application_processor/src/application_processor.c#L437) - - [component.c lines 198-203](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/component/src/component.c#L198) - -We need to be able to... - -- Replace a component (see [components](https://ectfmitre.gitlab.io/ectf-website/2024/specs/system_architecture.html#components)) currently connected to the system (see [MISC](https://ectfmitre.gitlab.io/ectf-website/2024/specs/system_architecture.html#medical-device)) -- Only replace a component if the replacement token is valid - -Functionally, we need to provide these outputs: - -|Level|Message format|Example| -|-----|--------------|-------| -|Success| `Replace\n` | `Replace\n`| -|Error| Any error message | `Replace failed\n` | - -### List Components - -- [High-level description](https://ectfmitre.gitlab.io/ectf-website/2024/specs/functional_reqs.html#list-components) -- [Detailed descripton](https://ectfmitre.gitlab.io/ectf-website/2024/specs/detailed_specs.html#list-components) -- Insecure example - - [application_processor.c lines 207-240](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/application_processor/src/application_processor.c#L207) - - [component.c lines 184-189](https://github.com/mitre-cyber-academy/2024-ectf-insecure-example/blob/release/component/src/component.c#L184) - -We need to be able to... - -- Print all the components (see [components](https://ectfmitre.gitlab.io/ectf-website/2024/specs/system_architecture.html#components)) currently connected to the system (see [MISC](https://ectfmitre.gitlab.io/ectf-website/2024/specs/system_architecture.html#medical-device)) -- Print all the components the system was provisioned for - -Functionally, we need to provide these outputs: - -|Level|Message format|Example| -|-----|--------------|-------| -|Info| `P>{Provisioned Component ID prefixed by 0x}\n` |`P>0x02\n` | -|Info| `F>{Found Component ID prefixed by 0x}\n` | `F>0x02\n` | -|Success| `List\n` | `List\n`| -|Error| Any error message | `Internal error\n` | - -### Security Requirements - -- [Security requirement 3](https://ectfmitre.gitlab.io/ectf-website/2024/specs/security_reqs.html#security-requirement-3) -- [Security requirement 4](https://ectfmitre.gitlab.io/ectf-website/2024/specs/security_reqs.html#security-requirement-4) - -## Development Stuff - -
- -### :pencil: Documentation - -Perhaps a surprising place to start for an embedded capture-the-flag competition, but this is probably the most important thing we will do. Even in computing, clear communication is king for everything from debugging to knowledge transfer. The same goes for eCTF, where documentation plays a big part in scoring for finalists. - -If you want an idea of what documentation for this type of project looks like, this is what our [final README](https://github.com/sigpwny/2023-ectf-sigpwny/blob/main/README.md) from last year looked like. I'm not expecting you to be super polished, but make sure you're keeping track of what you're doing and why you're doing it within the codebase and keep your commits somewhat descriptive (I won't be strict about it just make sure I could figure out what you did if I had to). - -As you might have noticed in the README, we also like to work with mermaid diagrams for visualizing protocols. If you're not familiar with mermaid, it's a way to make diagrams using text. It's a bit like markdown, but for diagrams. GitHub has integrated Mermaid support, so you can make diagrams in your markdown files and they'll render in the browser. - -Here's some resources to get you started with Mermaid: - -- [Mermaid live editor](https://mermaid-js.github.io/mermaid-live-editor/) -- [Mermaid documentation](https://mermaid-js.github.io/mermaid/#/) - -
- -### :crab: Rust (and Systems Programming Generally) - -Based on your survey responses, many of you don't have experience writing Rust code. I'm excited to introduce you to the language! I personally think Rust is more analogous to C++ than C, so if you've taken CS 128 or CS 225 or learned C++ some other way the skillset should translate. If you've taken ECE 220 or learned C some other way I don't think you'll run into too much trouble either. We will be installing Rust using the Nix environment proviced, so you don't need to worry about installing it. - -Here are some resources depending on what you're looking for! - -- [Official documentation book](https://doc.rust-lang.org/stable/book/) -- [Rust By Example](https://doc.rust-lang.org/rust-by-example/index.html) -- [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021) - -
- -### :snowflake: Nix - -We will be using Nix to manage our development environment. Nix (among other things) is a package manager that allows us to create isolated environments for our projects. For eCTF, it makes it easier for the organizers to ensure that everyone is working with the same environment and that we don't have to worry about dependencies conflicting with each other. Think about it kind of like Docker if you're familiar with that, or like a virtual environment in Python. Most of the Nix we do will be provided by the eCTF organizers, but we will need to install it and use it to manage our environment. - -- [Install Nix (just install the package manager, not the whole NixOS)](https://nixos.org/download.html) -- [Nix manual](https://nixos.org/manual/nix/stable/) - -
- -### :bed: Embedded Systems - -Embedded systems are new to a lot of people just getting started with eCTF, and to be honest they're not exactly my area of expertise as a CS major. The ECE majors in the room probably have a more solid background for how the hardware side of things works. - -If you want a virtual way to play with stuff like Arduinos, I've heard good things about [Wokwi](https://wokwi.com/), which lets you use Rust or Python to program virtual microcontrollers and wire projects. We probably won't be thinking a ton about embedded systems for our subteam, but it's good to have a general idea of how they work. - -## Security Stuff - -
- -### :lock: CIA Triad - -If you're not familiar with the CIA triad, it's a good place to start for understanding the security requirements of the eCTF. CIA stands for Confidentiality, Integrity, and Availability. - -__Confidentiality__ is about ensuring that only authorized users can access data. This is a big part of what we'll be doing with the attestation subteam! We need to make sure that the attestation data can only be accessed with the Attestation PIN and can't be brute forced or otherwise bypassed. - -__Integrity__ is about ensuring that data is not tampered with. If we can't trust that the data we're getting is accurate, we can't trust the system, which in a medical context is a big problem. We need to make sure that the attestation data can't be directly retrieved from the component, bypassing the application processor. - -__Availability__ is about ensuring that data is available when it's needed. There's no point in having a secure system if it's not usable! We need to make sure that the attestation data can be received by an authorized user with the Attestation PIN and that the replacement mechanism works when it's needed. - -When gaining an intuition for why vulnerabilites and security measures work, it's helpful to think about them in terms of the CIA triad. Make it a habit to look at a piece of code and think about its implications for confidentiality, integrity, and availability. - -
- -### :hourglass: Timing Attacks (and Side Channels Generally) - -Okay so let's say I have this function that checks for non-zero elements in an array. It looks like this: - -```c -int array_checker(int array[]) { - for (int i = 0; i < 100; i++) { - if (array[i] != 0) { - return 1; - } - } - return 0; -} -``` - -Let's say that given an arbitrary input, an array of 0s with a single non-zero element was generated. It's important that the attacker doesn't know where the non-zero element is. How could an attacker figure out where the element is anyways? - -Really think about it before you read on. A hint is that each line of code will take a certain amount of time to execute, let's say one unit of time per line to keep it simple (just know that this wil vary in practice). - -In this case, the attacker could see how long it takes for the function to return. The longer it takes, the farther into the array the first non-zero element is. This is a timing attack, which is a type of side channel attack. Another side channel attack is a power analysis attack, where an attacker can figure out what a device is doing based on how much power it's using. - -What might a more secure version of this function look like? A good place to start is making sure that the amount of time the function takes to execute doesn't give the attacker any information about the input. You could make the function take a constant amount of time to execute, or you could make it so that the time it takes to execute is random. - -
- -### :potato: Hashing and Argon2 - -If you aren't familiar with __hashing functions__, they're a way to take a piece of data and turn it into a fixed length string of characters. The inner workings are a bit outside of the scope of this competition, but if you're really interested in the math behind it, I can point you to some resources. - -We use hashing functions so that we don't have to store sensitive data like PINs and tokens in plaintext. A good hashing function should be hard to restore to the original data and should be hard to find duplicate inputs for (though because there are infinite strings of any length and limited strings of a fixed length, there will always be some). __Argon2__ is a password hashing function that's resistant to brute force and side channel attacks, so it's a good choice for hashing the PINs and tokens we'll be working with. - -One important aspect of hashes is that if you change a single character in the input, the hash will be completely different: - -```md -Input: "radsecret" -Argon2 hash: "bc7702f551781c9e7576898bcbeee3bf" - -Input: "ratsecret" -Argon2 hash: "05402972bc79f150f9cd0c9a1e72b32f" -``` - -This is called the __avalanche effect__. This is important because it means that the attacker will need to know the exact input to get the correct hash, and so protecting against brute force attacks becomes the priority. - -
- -### :salt: Salting - -We can make a hash even more robust using a technique called __salting__. Just for a bit of background, a common attack on hashed passwords is to use a precomputed table of hashes to find the original input. This is called a __rainbow table__, and it saves time for the attacker because they don't have to hash every possible input to find the original input. - -A salt is a random string we can add to an input before hashing it. This makes it harder for an attacker to use a precomputed table of hashes to find the original input. This works even if the attacker knows the salt, because they still cannot save time by using precomputed hashes to find the original input. This is all as simple as generating a random string and adding it to the input before hashing it! - -In another example of the avalanche effect, here are two hashes of the same input with different salts: - -```md -Input: "radsecret" -Salt: "mycoolsalt" -Argon2 hash: "bc7702f551781c9e7576898bcbeee3bf" - -Input: "radsecret" -Salt: "peppered" -Argon2 hash: "933b04ceeb18d8ed7eb28944cef2eab5" -``` \ No newline at end of file diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..16ad9b4 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,2 @@ +mermaid-filter.err +img/ \ No newline at end of file diff --git a/docs/1-overview.md b/docs/1-overview.md new file mode 100644 index 0000000..0f5ff21 --- /dev/null +++ b/docs/1-overview.md @@ -0,0 +1,17 @@ +\title{Medical Device (MISC) Design for MITRE eCTF 2024} +\author{SIGPwny at the University of Illinois Urbana-Champaign (UIUC)} + +\maketitle + +# Overview +This Design Document describes UIUC's implementation of the MISC system as defined by MITRE for eCTF 2024. The MISC system builds the platform for secure communication between medical devices through the use of a central Application Processor (AP) and various Components. While the reference design is considered insecure, our implementation aims to provide a secure and robust system that meets the security requirements outlined by MITRE. + +We started our design by analyzing the security requirements and creating the conceptual protocols and cryptographic schemes that would meet these requirements. + +## Rust + +Our design is built using Rust, a systems programming language that provides memory safety, a strong type system, and a minimal runtime. Crucially, Rust protects us from common security vulnerabilities such as buffer overflows. That being said, Rust is not a silver bullet, and we must still be careful to avoid other security pitfalls. + +There were quite a few challenges related to using Rust. In particular, the embedded platform that we are building on (Analog Devices MAX78000FTHR) did not have a stable, public Rust toolchain available online. To solve this, we implemented the peripheral drivers and built our own Hardware Abstraction Layer (HAL) from scratch. + +Another challenge was that we were required to support the execution of post boot code which is written in C. Not only that, but the C code needed to be able to call back into our Rust code in order to use our secure communication layer. This post boot code also requires the availability of functions from both the standard C library and the MSDK. We rewrote these functions in Rust and provided a C ABI for them so the linker could provide them to the post boot C code. \ No newline at end of file diff --git a/docs/2-hide_protocol.md b/docs/2-hide_protocol.md new file mode 100644 index 0000000..1bc34a1 --- /dev/null +++ b/docs/2-hide_protocol.md @@ -0,0 +1,96 @@ +# HIDE Protocol Communication Layer +We implement an extra communication layer between the I2C layer and the application layer, which we refer to as the HIDE protocol. The HIDE protocol ensures that all messages maintain confidentiality, integrity, authenticity, and non-replayability. We require all messages sent between the AP and the Component to use HIDE. + +HIDE effectively turns each application message into a three-way challenge-response handshake. The sender first initiates a message request. The receiver will then send a random, encrypted challenge. The sender will then decrypt the challenge, solve it, and encrypt the challenge response to be sent along with the actual message. To solve the challenge nonce, the sender must perform a bitwise XOR of `0x55` with each byte in the challenge nonce. + +We use the Authenticated Encryption (AE) cipher, [Ascon-128](https://ascon.iaik.tugraz.at/), for our cryptographic scheme. We chose Ascon since it was selected in the NIST Lightweight Cryptography competition and has a masked software implementation that has been tested against various power analysis and hardware attacks. + +We use Ascon's associated data feature to validate each message that uses encryption. The associated data is 8 bytes long, with the first 4 bytes being the component ID, the fifth byte being the HIDE message magic byte, and the last three bytes being null bytes. + +Each direction of communication uses a different symmetric encryption key, meaning there are two encryption keys: + +- $K_{AP,C}$ is the key for messages sent from the Application Processor to the Component. +- $K_{C,AP}$ is the key for messages sent from the Component to the AP. + +Every AP and Component built from the same deployment will share the same keys. This allows any Component to communicate with an AP from the same deployment. + +## HIDE Secure Protocol + +```{.mermaid loc=img #fig:hide-secure caption="HIDE secure communications protocol"} +sequenceDiagram + participant AP as Device A
Application Processor
(or Component) + participant C as Device B
Component
(or Application Processor) + + AP ->> C: HIDE_PKT_REQ_SECURE + + Note over C: Generates a challenge nonce + + C ->> AP: (HIDE_PKT_CHAL_SEND) + C -->> AP: (Unencrypted): Ascon Nonce A + C -->> AP: (Encrypted): Challenge Nonce + C -->> AP: (Encrypted): Random bytes + C -->> AP: (Unencrypted): Ascon Tag + + Note over AP: Receives, decrypts, and
solves the challenge nonce + + AP ->> C: (HIDE_PKT_CHAL_RESP) + AP -->> C: (Unencrypted): Ascon Nonce B + AP -->> C: (Encrypted): Solved Challenge Nonce + AP -->> C: (Encrypted): Message, padded with random bytes + AP -->> C: (Unencrypted): Ascon Tag + + alt Challenge Nonce Solve is Incorrect + Note over C: Reset transaction + end +``` + +If at any point the encryption or decryption of a HIDE message using the Ascon cipher fails (such as invalidation due to message bit-flips or incorrect associated data), our secure communication functions will return an error. + +Messages sent using HIDE can have a length up to 80 bytes. When HIDE interfaces are being used in the post boot code, the message length is limited to 64 bytes and the message length is encoded as an 8-bit integer in the first byte of the message. The remaining bytes are padded with random bytes. MISC messages are also limited to 64 bytes in length. + +### HIDE_PKT_REQ_SECURE +Sent by any device to initial a secure communication session with another device. This packet is unencrypted and contains the magic bytes corresponding to a secure request. + +| Name | Offset | Size (bytes) | Content | +| --------- | ------ | ------------ | ----------- | +| Magic | `0x00` | 10 | `\x40` * 10 | + +### HIDE_PKT_CHAL_SEND +Sent by the receiver of a secure request to initiate the challenge-response handshake. This packet contains the Ascon Nonce, the encrypted challenge nonce, and random bytes for padding. + +| Name | Offset | Size (bytes) | Content | +| ------------------------- | ------ | ------------ | ----------- | +| Ascon Nonce | `0x00` | 16 | `\x?? * 16` | +| Encrypted Challenge Nonce | `0x10` | 16 | `\x?? * 16` | +| Encrypted Random Bytes | `0x20` | 80 | `\x?? * 80` | +| Ascon Tag | `0x70` | 16 | `\x?? * 16` | + +> [!WARNING] +> Ascon Nonce should be randomly uniquely generated for all messages + +### CHAL_RESP +Sent by the sender of a secure request to complete the challenge-response handshake. This packet contains the Ascon Nonce, the encrypted solved challenge nonce, and the message to be sent. + +| Name | Offset | Size (bytes) | Content | +| -------------------------- | ------ | ------------ | ----------- | +| Ascon Nonce | `0x00` | 16 | `\x?? * 16` | +| Encrypted Solved Nonce | `0x10` | 16 | `\x?? * 16` | +| Encrypted Message + Random | `0x20` | 80 | `\x?? * 80` | +| Ascon Tag | `0x70` | 16 | `\x?? * 16` | + +> [!WARNING] +> Ascon Nonce should be randomly uniquely generated for all messages + +## HIDE List Protocol + +As part of the MISC system, we also must implement functionality to list all Components connected to the AP. We would use the HIDE secure protocol to enumerate I2C addresses and discover components, however, the HIDE secure protocol uses a Component's full ID as associated data during the encryption and decryption process. During this discovery process, we do not know the full ID of any Component with the exception of the Components which are provisioned for the AP. Even then, we cannot use these provisioned Component IDs in the case that a different valid Component shares the same I2C address. So, we decided to implement an extension to the HIDE protocol, which we refer to as the HIDE list protocol. This is only supported when the AP is communicating with a Component. + +The AP will send an unencrypted request packet which contains the magic bytes corresponding to a list request. The Component will then respond immediately with its 4-byte Component ID. + +```{.mermaid loc=img #fig:hide-list caption="HIDE list protocol"} +sequenceDiagram + participant AP as Application Processor + AP ->> C: (Unencrypted): HIDE_PKT_REQ_LIST + C ->> AP: (Unencrypted): Component ID + participant C as Component +``` \ No newline at end of file diff --git a/docs/2024_eCTF_UIUC_Design_Document.pdf b/docs/2024_eCTF_UIUC_Design_Document.pdf new file mode 100644 index 0000000..ea7854a Binary files /dev/null and b/docs/2024_eCTF_UIUC_Design_Document.pdf differ diff --git a/docs/3-misc_protocol.md b/docs/3-misc_protocol.md new file mode 100644 index 0000000..ca8982f --- /dev/null +++ b/docs/3-misc_protocol.md @@ -0,0 +1,222 @@ +# MISC Protocol + +The Medical Infrastructure Supply Chain (MISC) defines the functionality of our medical device design. We formerly describe protocols for each function in MISC. In order to maintain the secure operation of devices, all MISC messages are sent using the [HIDE protocol](./hide_protocol.md). + +> [!NOTE] +> "TTT" refers to "total transaction time" and is used to ensure timing functionality requirements are met. + +## List Components +The AP must be able to list Components which are currently connected to it, regardless of whether a Component has been provisioned for the AP. This is done by sending a HIDE list packet request to each possible I2C address. If a Component is present, it will respond with its Component ID. The AP will then log this Component ID to the host. + +Since listing a component is not considered a sensitive operation, there is no requirement to use secure communication. Additionally, performing a full HIDE challenge-response handshake for every possible I2C address would be time-consuming and unnecessary. The AP would also need to know the Component's ID in order to properly encrypt/decrypt a secure HIDE message. For these reasons, the HIDE list packet request was created as an extension to the HIDE protocol and allows the quick retrieval of a Component's ID without the need for secure communication. + +Note that the listing components protocol is an exception to the rest of the MISC protocol, which use the full HIDE protocol by sending a HIDE secure packet request. + +```{.mermaid loc=img #fig:list caption="List components protocol"} +sequenceDiagram + participant H as Host + participant AP as Application Processor + participant C as Component(s) + H ->> AP: "list" + loop For each provisioned component + AP ->> H: Info: "P>0x" + Component ID + end + loop For each I2C address + AP ->> C: HIDE List Packet Request + alt C is attached and responsive + C ->> AP: Component ID + AP ->> H: Info: "F>0x" + Component ID + else C is unresponsive + Note over AP: No response needed, continue + end + end + AP -x H: Success: "List" +``` + +Specific message packet formats are not defined for the list components protocol, since this is defined by the HIDE protocol. + +## Attest Components +Every Component stores Attestation Data which is used to verify the authenticity of the Component. This Attestation Data is protected by a 6-byte Attestation PIN, which must be stored and validated on an AP. Thus, the communications between the AP and the Component must be authentic and secure in order to prevent possible attacks to extract the Attestation Data through bypassing the AP. The HIDE protocol is used to ensure this secure communication. + +In order to protect the Attestation PIN from being compromised, the AP stores the Attestation PIN as three uniquely salted SHA3-512 hashes. The salt is a random 16-byte string that is generated during the AP's build process and is prepended to the Attestation PIN before hashing. Each salt and hash pair is stored in the AP so that the Attestation PIN is never stored in plaintext. + +The transfer of the Attestation Data is broken into three parts in order to meet length requirements of the HIDE protocol. The AP will first request the Component's Attestation Location, then the Attestation Date, and finally the Attestation Customer. The Component will respond with each of these pieces of information in turn. Only once the AP has received all three pieces of information will it send the Attestation Data to the host. + +Additionally, a fixed transaction delay of 2.5 seconds is sent in place to prevent brute force attacks. + + +```{.mermaid loc=img #fig:attest caption="Attest components protocol"} +sequenceDiagram + participant H as Host + participant AP as Application Processor + participant C as Component + H ->> AP: "attest" + H ->> AP: PIN Attempt + H ->> AP: Component ID + loop For each N Salt-Hash pair + Note over AP: Compute SHA3-512(Salt N, Attest PIN attempt)
and compare with stored Hash N + end + Note over H, C: Minimum 2.5 seconds TTT elapsed + alt Any hash is incorrect + Note over H, C: Delay for an additional 5s + AP -x H: Error: "Attest failed" + else + AP ->> C: REQUEST_LOCATION + C ->> AP: Attestation Location + AP ->> C: REQUEST_DATE + C ->> AP: Attestation Date + AP ->> C: REQUEST_CUSTOMER + C ->> AP: Attestation Customer + AP ->> H: Info: "C>0x" + Component ID + AP ->> H: Info: "LOC>" + Location + AP ->> H: Info: "DATE>" + Date + AP ->> H: Info: "CUST>" + Customer + AP -x H: Success: "Attest" + Note over H: <3s TTT on success + end +``` + + +### REQUEST_LOCATION +The Application Processor sends this message to the Component to request the Component's Attestation Location. The Component will respond with its Attestation Location. + +| Name | Offset | Size (bytes) | Content | +| --------- | ------ | ------------ | ------------ | +| Magic | `0x00` | 80 | `\x60` * 80 | + +### SEND_LOCATION +The Component sends this message to the Application Processor in response to a REQUEST_LOCATION. This message only contains the Component's Attestation Location. + +| Name | Offset | Size (bytes) | Content | +| ---------------- | ------ | ------------ | ------------------ | +| Location | `0x00` | 64 | `\x?? * 64` | + +### REQUEST_DATE +The Application Processor sends this message to the Component to request the Component's Attestation Date. The Component will respond with its Attestation Date. + +| Name | Offset | Size (bytes) | Content | +| --------- | ------ | ------------ | ------------ | +| Magic | `0x00` | 80 | `\x62` * 80 | + +> [!WARNING] +> The Component should not respond to a REQUEST_DATE if it has not received a REQUEST_LOCATION beforehand. + +### SEND_DATE +The Component sends this message to the Application Processor in response to a REQUEST_DATE. This message only contains the Component's Attestation Date. + +| Name | Offset | Size (bytes) | Content | +| ---------------- | ------ | ------------ | ------------------ | +| Date | `0x00` | 64 | `\x?? * 64` | + +### REQUEST_CUSTOMER +The Application Processor sends this message to the Component to request the Component's Attestation Customer. The Component will respond with its Attestation Customer. + +| Name | Offset | Size (bytes) | Content | +| --------- | ------ | ------------ | ------------ | +| Magic | `0x00` | 80 | `\x64` * 80 | + +### SEND_CUSTOMER +The Component sends this message to the Application Processor in response to a REQUEST_CUSTOMER. This message only contains the Component's Attestation Customer. + +| Name | Offset | Size (bytes) | Content | +| ---------------- | ------ | ------------ | ------------------ | +| Customer | `0x00` | 64 | `\x?? * 64` | + +> [!WARNING] +> The Component should not respond to a REQUEST_CUSTOMER if it has not received a REQUEST_DATE beforehand. + +## Replace Components +The AP keeps tracks of Components which are provisioned for it by storing their Component IDs. When a Component is replaced, the AP will update its list of provisioned Components with the new Component ID. + +Because this is a sensitive operation, the AP requires a Replacement Token to be sent by the host to validate the replacement. The Replacement Token is a 16-byte string that is assigned during the AP's build process. The Replacement Token is used to ensure that the host is authorized to replace the Component. + +In order to protect the Replacement Token from being compromised, the AP stores the Replacement Token as three uniquely salted SHA3-512 hashes. The salt is a random 16-byte string that is generated during the AP's build process and is prepended to the Replacement Token before hashing. Each salt and hash pair is stored in the AP so that the Replacement Token is never stored in plaintext. + +Additionally, a fixed transaction delay of 4.5 seconds is sent in place to prevent brute force attacks. + +```{.mermaid loc=img #fig:replace caption="Replace components protocol"} +sequenceDiagram + participant H as Host + participant AP as Application Processor + H ->> AP: "replace" + H ->> AP: Replacement Token attempt + H ->> AP: New Component ID + H ->> AP: Old Component ID + loop For each N Salt-Hash pair + Note over AP: Compute SHA3-512(Salt N, Replacement Token attempt)
and compare with stored Hash N + end + Note over H, AP: Minimum 4.5 seconds TTT elapsed + alt Any hash is incorrect + Note over H, AP: Delay for an additional 5s + AP -x H: Error: "Replace failed" + else + Note over AP: Update Component ID list
with new Component ID + AP -x H: Success: "Replace" + Note over H: <5s TTT on success + end + +``` + +## Boot Verification +The boot verification process is used to ensure that the Application Processor (AP) only boots if all expected Components are present and valid. The AP will verify that each Component is attached and responsive before booting. The AP will then collect each Component's boot message and send it to the host. + +```{.mermaid loc=img #fig:boot caption="Boot verification protocol"} +sequenceDiagram + participant H as Host + participant AP as Application Processor + participant C as Component + H ->> AP: "boot" + loop For each provisioned Component + AP ->> C: BOOT_PING + alt Component is attached and responsive + C ->> AP: BOOT_PONG + Note over AP: Continue + else Component is unresponsive + Note over AP: Abort boot + AP -x H: Error: "Boot failed" + end + end + Note over H, C: AP has verified each Component is attached and responsive + loop For each provisioned Component + AP ->> C: BOOT_NOW + C -->> AP: Component's Boot Message + Note over C: Component enters POST_BOOT + end + Note over H, C: AP has collected all Component boot messages + loop For each provisioned Component + AP ->> H: Info: Component's Boot Message + end + AP ->> H: Info: AP's Boot Message + AP -x H: Success: "Boot" + Note over AP: AP enters POST_BOOT + Note over H: <3s TTT on success +``` + +### BOOT_PING +Sent from the Application Processor to each Component to "ping" the Component to ensure it is attached and responsive. Expected to receive a BOOT_PONG in response. + +| Name | Offset | Size (bytes) | Content | +| --------- | ------ | ------------ | ------------ | +| Magic | `0x00` | 80 | `\x80` * 80 | + +### BOOT_PONG +Sent from the Component to the Application Processor in response to a BOOT_PING. This indicates that the Component is attached and responsive. + +| Name | Offset | Size (bytes) | Content | +| --------- | ------ | ------------ | ------------ | +| Magic | `0x00` | 80 | `\x81` * 80 | + +### BOOT_NOW +Sent from the Application Processor to each Component to command the Component to boot. The Component will then send its boot message (of length 64) to the Application Processor. + +| Name | Offset | Size (bytes) | Content | +| --------- | ------ | ------------ | ------------ | +| Magic | `0x00` | 80 | `\x82` * 80 | + +> [!WARNING] +> The component should not respond to a BOOT_NOW if it has not received a BOOT_PING beforehand. + +## Post-Boot Communication +As part of the MISC requirements, both the AP and Component must be able to enter a POST_BOOT state, where arbitrary C code runs to support medical device operation. The AP and Component must be able to communicate with each other in this state, so interfaces for HIDE secure send and receive are defined. + +For more information about the HIDE protocol, please see the [HIDE protocol documentation](./hide_protocol.md). \ No newline at end of file diff --git a/docs/4-security_requirements.md b/docs/4-security_requirements.md new file mode 100644 index 0000000..6bc4196 --- /dev/null +++ b/docs/4-security_requirements.md @@ -0,0 +1,33 @@ +# Security Requirements + +Below we summarize how we achieve the outlined security requirements with our design. + +## Security Requirement 1 + +> *"The Application Processor (AP) should only boot if all expected Components are present and valid."* + +Because of the integrity, authenticity, and non-replayability properties of the HIDE protocol, we ensure that the AP is actively communicating with valid, provisioned Components from the same deployment. A counterfeit Component will not be built on the same deployment and thus will not have access to the Ascon-128 keys required for the encryption layer. + +## Security Requirement 2 + +> *"Components should only boot after being commanded to by a valid AP that has confirmed the integrity of the device."* + +After the AP verifies that each Component is connected and valid, the AP will command each Component to boot. Each Component takes advantage of the integrity, authenticity, and non-replayability properties of the HIDE protocol to confirm that the AP has truly commanded the Component to boot. + +## Security Requirement 3 + +> *"The Attestation PIN and Replacement Token should be kept confidential."* + +We use multiple SHA3-512 hashes to validate the Attestation PIN and Replacement Token, preventing compromise of the real PIN and token through side-channel analysis. We also use timers and random delays to effectively prevent brute force and further side-channel attacks. + +## Security Requirement 4 + +> *"Component Attestation Data should be kept confidential."* + +Attestation Data is only provided to the AP if the Component receives a command from the AP instructing it to provide Attestation Data. This command is only sent if the AP successfully validates the Attestation PIN. This command cannot be forged due to the properties of the HIDE protocol. + +## Security Requiremenet 5 + +> *"The integrity and authenticity of messages sent and received using the post-boot MISC secure communications functionality should be ensured."* + +The HIDE communication layer uses authenticated encryption with Ascon-128 to verify the authenticity of the sender and receiver. The challenge-response nature of the HIDE protocol and the use of nonces prevents the replay of messages. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d54605a --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,11 @@ +default: + @echo "Building the Design Document" + @pandoc -F mermaid-filter -t markdown \ + 1-overview.md \ + newpage.tex \ + 2-hide_protocol.md \ + newpage.tex \ + 3-misc_protocol.md \ + newpage.tex \ + 4-security_requirements.md \ + | pandoc --number-sections -V geometry:margin=1.5in -F pandoc-crossref --pdf-engine=tectonic -o 2024_eCTF_UIUC_Design_Document.pdf \ No newline at end of file diff --git a/docs/dependencies.sh b/docs/dependencies.sh deleted file mode 100755 index 3cef2ba..0000000 --- a/docs/dependencies.sh +++ /dev/null @@ -1,2 +0,0 @@ -sudo npm install -g npm@6.14.18 -sudo npm install --global mermaid-filter \ No newline at end of file diff --git a/docs/flash.md b/docs/flash.md deleted file mode 100644 index cd6f92e..0000000 --- a/docs/flash.md +++ /dev/null @@ -1,50 +0,0 @@ -# Flash State -In order to store state and sensitive data that needs to persist across reboots, we use flash memory with fixed addresses. - -Our firmware is limited to flash addresses `0x1000_E000` - `0x1004_5FFF`. On the MAX78000, flash is separated into pages of 8192 bytes. We store our state in the last two flash pages available to us: - -- `0x1004_2000` - `0x1004_3FFF` -- `0x1004_4000` - `0x1004_5FFF` - -We use two separate flash pages since we need to update Component IDs that were replaced during the Replacement command in the Application Processor. Flash can only be written in one direction (`1` to `0`) and thus require erases followed by writes if we would like to update a specific flash address. Flash can only be erased in full pages, so we use the last page of flash as a read-write page for storing/updating Component IDs. Only the Application Processor has its last page (`0x1004_4000`) available as read-write. The same page (`0x1004_4000`) for the Component is read only and stores the Component's own ID. - -## Application Processor Flash State -``` -0x1000_0000 ┌───────────────────────┬─────┬────┐ -0x1000_E000 │ AP Firmware │ │ R │ - │ │ │ │ - │ │ │ │ -0x1004_0000 ├───────────────────────┼─────┼────┤ -0x1004_0000 │ Boot Message │ 64B │ R │ - │ │ │ │ -0x1004_1000 │ Ascon Key (AP -> C) │ 16B │ R │ -0x1004_1080 │ Ascon Key (C -> AP) │ 16B │ R │ -0x1004_1400 │ Attest PIN Hash │ 32B │ R │ -0x1004_1480 │ Attest PIN Salt │ 16B │ R │ -0x1004_1800 │ Replace Token Hash │ 32B │ R │ -0x1004_1880 │ Replace Token Salt │ 16B │ R │ -0x1004_2000 ├───────────────────────┼─────┼────┤ -0x1004_2000 │ Prov. Component ID 1 │ 4B │ RW │ -0x1004_4000 ├───────────────────────┼─────┼────┤ -0x1004_4000 │ Prov. Component ID 0 │ 4B │ RW │ -0x1004_6000 └───────────────────────┴─────┴────┘ -``` - -## Component Flash State -``` -0x1000_0000 ┌───────────────────────┬─────┬────┐ -0x1000_E000 │ Component Firmware │ │ R │ - │ │ │ │ - │ │ │ │ -0x1004_2000 ├───────────────────────┼─────┼────┤ -0x1004_2000 │ Boot Message │ 64B │ R │ -0x1004_2100 │ Attest Location │ 64B │ R │ -0x1004_2200 │ Attest Date │ 64B │ R │ -0x1004_2300 │ Attest Customer │ 64B │ R │ - │ │ │ │ -0x1004_3000 │ Ascon Key (AP -> C) │ 16B │ R │ -0x1004_3080 │ Ascon Key (C -> AP) │ 16B │ R │ -0x1004_4000 ├───────────────────────┼─────┼────┤ -0x1004_XXXX │ Component ID (Self) │ 4B │ R │ -0x1004_6000 └───────────────────────┴─────┴────┘ -``` diff --git a/docs/hide_protocol.md b/docs/hide_protocol.md deleted file mode 100644 index 59a50f2..0000000 --- a/docs/hide_protocol.md +++ /dev/null @@ -1,76 +0,0 @@ -# HIDE Protocol Communication Layer -We implement an extra communication layer between the I2C layer and the application layer, which we refer to as the HIDE protocol. The HIDE protocol ensures that all messages maintain confidentiality, integrity, authenticity, and non-replayability. We require all messages sent between the AP and the Component to use HIDE. - -HIDE effectively turns each message into a three-way challenge-response handshake. The sender first initiates a message request. The receiver will then send a random, encrypted challenge. The sender will then decrypt the challenge, solve it, and encrypt the challenge response to be sent along with the actual message. To solve the challenge nonce, the sender must perform a bitwise XOR of `0x55` with each byte in the challenge nonce. - -We use the Authenticated Encryption (AE) cipher, Ascon, for our cryptographic scheme. We chose Ascon since it was selected in the NIST Lightweight Cryptography competition and has a masked software implementation that has been tested against various power analysis and hardware attacks. - -## HIDE Protocol - -```mermaid -sequenceDiagram -participant AP as Device A
Application Processor
(or Component) -participant C as Device B
Component
(or Application Processor) - -AP ->> C: MSG_REQ - -Note over C: Component generates and stores nonce - -C ->> AP: (Challenge Send) -C -->> AP: (Unencrypted): Ascon Nonce A -C -->> AP: (Encrypted): Challenge Nonce -C -->> AP: (Encrypted): Random bytes - -Note over AP: Application Processor decrypts
and solves the challenge - -AP ->> C: (Challenge Response) -AP -->> C: (Unencrypted): Ascon Nonce B -AP -->> C: (Encrypted): Challenge Nonce XOR 0x55 -AP -->> C: (Encrypted): Message, padded with random bytes - -alt Challenge Nonce XOR 0x55 Incorrect - Note over C: Component resets to default state -end -``` - -We use Ascon's associated data feature to validate each message. The associated data is 8 bytes, with the first 4 bytes being the component ID, the fifth byte being the HIDE message magic byte, and the last three bytes being null bytes. - -Each direction of communication uses a different symmetric encryption key, meaning there are two encryption keys: - -- $K_{AP,C}$ is the key for messages sent from the Application Processor to the Component. -- $K_{C,AP}$ is the key for messages sent from the Component to the AP. - -Every AP and Components built from the same deployment will share the same keys. - -### MSG_REQ -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x40` | - -### CHAL_SEND -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Ascon Nonce | `0x00` | 16 | `\x?? * 16` | -| Encrypted data | `0x10` | 96 | Challenge Nonce (16 bytes) + Random bytes (80 bytes) | - -> [!WARNING] -> Ascon Nonce should be randomly uniquely generated for all messages - -### CHAL_RESP -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Ascon Nonce | `0x00` | 16 | `\x?? * 16` | -| Encrypted data | `0x10` | 96 | Solved Challenge Nonce (16 bytes) + Message, padded with random bytes (80 bytes) | - - -> [!WARNING] -> Ascon Nonce should be randomly uniquely generated for all messages - -> [!NOTE] -> Application messages can only be a maximum of 64 bytes. We provide up to 80 bytes for posterity. diff --git a/docs/img/.gitkeep b/docs/img/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/make_doc.sh b/docs/make_doc.sh deleted file mode 100755 index f5c5644..0000000 --- a/docs/make_doc.sh +++ /dev/null @@ -1 +0,0 @@ -pandoc --number-sections hide_protocol.md misc_protocol.md flash.md -F mermaid-filter -o UIUC_Documentation.pdf --pdf-engine=tectonic \ No newline at end of file diff --git a/docs/misc_protocol.md b/docs/misc_protocol.md deleted file mode 100644 index 22201f9..0000000 --- a/docs/misc_protocol.md +++ /dev/null @@ -1,217 +0,0 @@ -# MISC Protocol - -Description TODO. All MISC messages are sent over the [HIDE protocol](./hide_protocol.md). - -> [!NOTE] -> "TTT" refers to "total transaction time" and is used to ensure timing functionality requirements are met. - -## List Components -The host will ask the Application Processor to "list" its components. -The Application Processor, upon receiving the message from the host, will list its provisioned components. -It will then send a magic byte as a ping to every I2C address. For components that are present and responsive, they will send a magic byte pong as well as its component ID, which will prompt the Application Processor to send the component ID to the host. - -```mermaid -sequenceDiagram - participant H as Host - participant AP as Application Processor - participant C as Component(s) - H ->> AP: "list\r" - loop For each provisioned component - AP ->> H: Info: "P>0x" + CID + "\n" - end - loop For each I2C addr - AP ->> C: LIST_PING - alt C is attached and responsive - C ->> AP: LIST_PONG - C -->> AP: CID - AP ->> H: Info: "F>0x" + CID + "\n" - else C is unresponsive - Note over AP: No response needed, continue - end - end - AP -x H: Success: "List\n" -``` - - -### LIST_PING -This byte is sent to every I2C address. For present components, this indicates that the Application Processor is asking for its component ID. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x50` | - -### LIST_PONG -After being prompted by the Application Processor using LIST_PING, an active component will send a response byte and the component ID to the Application Processor. - -| Name | Offset | Size (bytes) | Content | -| ------------ | ----------- | ------------ | ------------------ | -| Magic | `0x00` | 1 | `\x51` | -| Component ID | `0x01-0x05` | 4 | `\x??\x??\x??\x??` | - - -## Attest Components -Description TODO. - -> [!NOTE] -> The PIN attempt and component ID need to be transmitted at the beginning in a way that the host tool can understand. - -```mermaid -sequenceDiagram - Host ->> AP: "attest\r" - Host ->> AP: PIN Attempt - Host ->> AP: Component ID - Note over Host, Component: Minimum 0.8 TTT elapsed - Note over AP: Compute Argon 2 hash from salt
and PIN attempt, compare
computed hash and stored hash - Note over Host, Component: Minimum 2.8s TTT elapsed - alt PIN is incorrect - Note over Host, Component: Delay for an additional 5s - AP -x Host: Error: "Attest failed\n" - else - AP ->> Component: REQUEST_LOCATION - Component ->> AP: SEND_LOCATION - AP ->> Component: REQUEST_DATE - Component ->> AP: SEND_DATE - AP ->> Component: REQUEST_CUSTOMER - Component ->> AP: SEND_CUSTOMER - AP ->> Host: Info: "C>0x" + CID "\n" - AP ->> Host: Info: "LOC>" + Location "\n" - AP ->> Host: Info: "DATE>" + Date "\n" - AP ->> Host: Info: "CUST>" + Customer "\n" - AP -x Host: Success: "Attest\n" - end -``` - - -### REQUEST_LOCATION -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x60` | - -### SEND_LOCATION -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| ---------------- | ------ | ------------ | ------------------ | -| Magic | `0x00` | 1 | `\x61` | -| Location | `0x01` | 64 | `\x?? * 64` | - -### REQUEST_DATE -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x62` | - -### SEND_DATE -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| ---------------- | ------ | ------------ | ------------------ | -| Magic | `0x00` | 1 | `\x63` | -| Date | `0x01` | 64 | `\x?? * 64` | - -### REQUEST_CUSTOMER -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x64` | - -### SEND_CUSTOMER -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| ---------------- | ------ | ------------ | ------------------ | -| Magic | `0x00` | 1 | `\x65` | -| Customer | `0x01` | 64 | `\x?? * 64` | - -## Replace Components -Description TODO. - -```mermaid -sequenceDiagram - participant H as Host - participant AP as Application Processor - H ->> AP: Replacement Token - H ->> AP: Old Component ID - H ->> AP: New Component ID - Note over H, AP: 3 seconds elapsed - Note over AP: Compute Argon2 hash of
salt | Replacement Token - Note over H, AP: 4.8 seconds TTT elapsed - alt Replacement Token Incorrect - AP -x H: Error: "Replace failed\n" - else - Note over AP: Update Component ID list
with new Component ID - AP -x H: Success: "Replace\n" - end - -``` - -## Boot Verification -Description TODO. - -```mermaid -sequenceDiagram - participant H as Host - participant AP as Application Processor - participant C1 as Component 1 - participant C2 as Component 2 - H ->> AP: "boot\r" - Note over AP, C2: BOOT_PINGs are sent in order, one at a time - AP ->> C1: BOOT_PING - alt C1 is attached and responsive - C1 ->> AP: BOOT_PONG - Note over AP: Continue - else C1 is unresponsive - Note over AP: Abort boot - AP -x H: Error: "Boot failed!\n" - end - AP ->> C2: BOOT_PING - alt C2 is attached and responsive - C2 ->> AP: BOOT_PONG - Note over AP: Continue - else C2 is unresponsive - Note over AP: Abort boot - AP -x H: Error: "Boot failed!\n" - end - Note over H, C2: Minimum 2.8s TTT elapsed - AP ->> C1: BOOT_NOW - C1 -->> AP: C1 Boot Message - Note over C1: C1 enters POST_BOOT - AP ->> C2: BOOT_NOW - C2 -->> AP: C2 Boot Message - Note over C2: C2 enters POST_BOOT - AP ->> H: "Boot Success" - AP -->> H: AP Boot Message - AP -->> H: C1 Boot Message - AP -->> H: C2 Boot Message - Note over AP: AP enters POST_BOOT - Note over H: <3s TTT on success -``` - -### BOOT_PING -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x80` | - -### BOOT_PONG -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x81` | - -### BOOT_NOW -Description TODO. - -| Name | Offset | Size (bytes) | Content | -| --------- | ------ | ------------ | ------- | -| Magic | `0x00` | 1 | `\x82` | - -## Post-Boot Communication -Description TODO. - diff --git a/docs/newpage.tex b/docs/newpage.tex new file mode 100644 index 0000000..dc41495 --- /dev/null +++ b/docs/newpage.tex @@ -0,0 +1 @@ +\newpage \ No newline at end of file diff --git a/docs/run_once.sh b/docs/run_once.sh deleted file mode 100755 index dfcf02a..0000000 --- a/docs/run_once.sh +++ /dev/null @@ -1,4 +0,0 @@ -chmod +x dependencies.sh -chmod +x make_doc.sh -nix-shell shell.nix -./dependencies.sh \ No newline at end of file diff --git a/docs/shell.nix b/docs/shell.nix deleted file mode 100644 index bebd556..0000000 --- a/docs/shell.nix +++ /dev/null @@ -1,11 +0,0 @@ -# shell.nix - -{ pkgs ? import {} }: - -pkgs.mkShell { - buildInputs = [ - pkgs.pandoc - pkgs.nodejs - pkgs.tectonic - ]; -} \ No newline at end of file diff --git a/rust-lib/ascon/src_c/origin.txt b/rust-lib/ascon/src_c/origin.txt index 66bd663..8a36d44 100644 --- a/rust-lib/ascon/src_c/origin.txt +++ b/rust-lib/ascon/src_c/origin.txt @@ -1 +1 @@ -https://github.com/ascon/ascon-c/crypto_aead/ascon128v12/armv7m_lowsize +https://github.com/ascon/ascon-c/tree/main/crypto_aead/ascon128v12/armv7m_lowsize \ No newline at end of file diff --git a/rust-lib/ectf-board/src/ectf_constants.rs b/rust-lib/ectf-board/src/ectf_constants.rs index dafde23..597524a 100644 --- a/rust-lib/ectf-board/src/ectf_constants.rs +++ b/rust-lib/ectf-board/src/ectf_constants.rs @@ -17,11 +17,8 @@ pub const LEN_SHA3_512_HASH: usize = 64; // MISC magic bytes pub const MAGIC_MISC_REQ_LOCATION: u8 = 0x60; -pub const MAGIC_MISC_SEND_LOCATION: u8 = 0x61; pub const MAGIC_MISC_REQ_DATE: u8 = 0x62; -pub const MAGIC_MISC_SEND_DATE: u8 = 0x63; pub const MAGIC_MISC_REQ_CUSTOMER: u8 = 0x64; -pub const MAGIC_MISC_SEND_CUSTOMER: u8 = 0x65; pub const MAGIC_MISC_BOOT_PING: u8 = 0x80; pub const MAGIC_MISC_BOOT_PONG: u8 = 0x81; pub const MAGIC_MISC_BOOT_NOW: u8 = 0x82; diff --git a/rust-lib/ectf-board/src/lib.rs b/rust-lib/ectf-board/src/lib.rs index 009b0c4..43f8aed 100644 --- a/rust-lib/ectf-board/src/lib.rs +++ b/rust-lib/ectf-board/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] pub mod secure_comms; -pub mod post_boot_shared; +pub mod rng; pub mod ectf_constants; pub mod ectf_global_secrets; @@ -9,7 +9,10 @@ pub use max78000_pac as pac; pub use max78000_hal as hal; use max78000_hal::{*}; use ectf_constants::{*}; -use core::panic::PanicInfo; +use rand::RngCore; +use rng::CustomRng; +use core::{cell::RefCell, panic::PanicInfo}; +use core::arch::asm; pub enum Led { Red = 0, @@ -17,6 +20,17 @@ pub enum Led { Blue = 2, } +impl Led { + pub fn from_u32(value: u32) -> Option { + match value { + 0 => Some(Led::Red), + 1 => Some(Led::Green), + 2 => Some(Led::Blue), + _ => None, + } + } +} + pub struct Board { pub flc: pac::FLC, pub gcr: pac::GCR, @@ -25,15 +39,20 @@ pub struct Board { pub i2c1: pac::I2C1, pub tmr0: pac::TMR, pub tmr1: pac::TMR1, + pub tmr2: pac::TMR2, + pub tmr4: pac::TMR4, pub trng: pac::TRNG, pub uart0: pac::UART, + rng: RefCell, } +// Safety: Board is a singleton and we only use one core. +unsafe impl Sync for Board {} + impl Board { /// Create a new Board instance - pub fn new() -> Self { - // Safety: We only steal the peripherals once and we have exclusive access - let p: pac::Peripherals = unsafe { pac::Peripherals::steal() }; + pub fn new(seed: [u8; 64]) -> Self { + let p: pac::Peripherals = pac::Peripherals::take().unwrap(); // Initialize clocks gcr::system_clock_ipo_init(&p.GCR); gcr::iso_init(&p.GCR); @@ -54,6 +73,16 @@ impl Board { gcr::mxc_tmr1_shutdown(&p.GCR); gcr::mxc_tmr1_enable_clock(&p.GCR); gpio0::config(&p.GPIO0, gpio0::GPIO0_CFG_TMR1); + // Initialize TMR2 (entropy source) + gcr::mxc_tmr2_shutdown(&p.GCR); + gcr::mxc_tmr2_enable_clock(&p.GCR); + gpio0::config(&p.GPIO0, gpio0::GPIO0_CFG_TMR2); + tmr2::config(&p.TMR2); + // Initialize TMR4 (entropy source) + gcr::mxc_tmr4_shutdown(&p.LPGCR); + gcr::mxc_tmr4_enable_clock(&p.LPGCR); + gpio2::config(&p.GPIO2, gpio2::GPIO2_CFG_TMR4); + tmr4::config(&p.TMR4); // Initialize TRNG gcr::mxc_trng_shutdown(&p.GCR); gcr::mxc_trng_enable_clock(&p.GCR); @@ -69,6 +98,8 @@ impl Board { gcr::mxc_i2c1_shutdown(&p.GCR); gcr::mxc_i2c1_enable_clock(&p.GCR); gpio0::config(&p.GPIO0, gpio0::GPIO0_CFG_I2C1); + // Create custom RNG instance + let rng = CustomRng::new(&p.TMR2, &p.TMR4, &p.TRNG, seed); // Return the Board instance Board { flc: p.FLC, @@ -78,8 +109,11 @@ impl Board { i2c1: p.I2C1, tmr0: p.TMR, tmr1: p.TMR1, + tmr2: p.TMR2, + tmr4: p.TMR4, trng: p.TRNG, uart0: p.UART, + rng: RefCell::new(rng), } } @@ -115,7 +149,7 @@ impl Board { /// Block for a random number of microseconds between min and max pub fn delay_timer_wait_random_us(&self, min: u32, max: u32) { - let random = trng::random_u32(&self.trng); + let random = self.next_u32(); let max_ticks = tmr1::us_to_ticks(max); let min_ticks = tmr1::us_to_ticks(min); let ticks = min_ticks + (random % (max_ticks - min_ticks)); @@ -242,20 +276,44 @@ impl Board { /// Read a command from the host (terminated by '\r') /// Definitely safe :) pub fn gets(&self, buffer: &mut [u8]) -> Option { - let mut index = 0; - for byte in buffer.iter_mut() { - let result = uart0::read_byte(&self.uart0); - *byte = result; - // Echo the received byte - uart0::write_byte(&self.uart0, result); - if result == b'\r' { - return Some(index); + let mut num_read = 0; + for out_byte in buffer.iter_mut() { + let in_byte = uart0::read_byte(&self.uart0); + uart0::write_byte(&self.uart0, in_byte); + *out_byte = in_byte; + if in_byte == b'\r' { + return Some(num_read); } - index += 1; + num_read += 1; } return None; } + /// Read from UART, safe for C by rewriting input '\r' as '\n' + /// Intended for POST_BOOT C code, based on MSDK stdio.c implementation + pub fn libc_read_uart(&self, buffer: &mut [u8]) { + for out_byte in buffer.iter_mut() { + let in_byte = uart0::read_byte(&self.uart0); + uart0::write_byte(&self.uart0, in_byte); + if in_byte == b'\r' { + *out_byte = b'\n'; + break; + } + *out_byte = in_byte; + } + } + + /// Write to UART, rewrites output byte '\n' as '\r\n' + /// Intended for POST_BOOT C code, based on MSDK stdio.c implementation + pub fn libc_write_uart(&self, buffer: &[u8]) { + for byte in buffer.iter() { + if *byte == b'\n' { + uart0::write_byte(&self.uart0, b'\r'); + } + uart0::write_byte(&self.uart0, *byte); + } + } + /// Write 4 bytes to flash at the given address (erases the flash page if necessary) pub fn write_flash_bytes(&self, addr: u32, data: &[u8; 4]) { let result = flc::write_32(&self.flc, addr, bytes_to_u32(data)); @@ -318,6 +376,7 @@ impl Board { } } + /// Turn on the specified LED pub fn led_on(&self, led: Led) { match led { Led::Red => gpio2::set_out(&self.gpio2, gpio2::GPIO2_CFG_LED0.pins), @@ -326,6 +385,7 @@ impl Board { } } + /// Turn off the specified LED pub fn led_off(&self, led: Led) { match led { Led::Red => gpio2::clr_out(&self.gpio2, gpio2::GPIO2_CFG_LED0.pins), @@ -334,6 +394,7 @@ impl Board { } } + /// Toggle the specified LED pub fn led_toggle(&self, led: Led) { match led { Led::Red => gpio2::toggle_out(&self.gpio2, gpio2::GPIO2_CFG_LED0.pins), @@ -341,6 +402,35 @@ impl Board { Led::Blue => gpio2::toggle_out(&self.gpio2, gpio2::GPIO2_CFG_LED2.pins), } } + + // Not RngCore because we are doing the interior mutability stuff :(( + /// Generate random bytes + pub fn fill_bytes(&self, dest: &mut [u8]) { + critical_section::with(|_| { + self.rng.borrow_mut().fill_bytes(dest) + }) + } + + /// Generate a random u32 + pub fn next_u32(&self) -> u32 { + critical_section::with(|_| { + self.rng.borrow_mut().next_u32() + }) + } + + /// Generate a random u64 + pub fn next_u64(&self) -> u64 { + critical_section::with(|_| { + self.rng.borrow_mut().next_u64() + }) + } + + /// Try to generate random bytes + pub fn try_fill_bytes(&self, dest: &mut [u8]) -> Result<(), rand::Error> { + critical_section::with(|_| { + self.rng.borrow_mut().try_fill_bytes(dest) + }) + } } /// Lock all flash pages except: @@ -418,19 +508,85 @@ pub fn bytes_to_u32(data: &[u8; 4]) -> u32 { ((data[3] as u32) << 24) } +///🙄 #[panic_handler] pub fn panic(_info: &PanicInfo) -> ! { - // Safety: We're panicking, nothing is safe anymore - let p = unsafe { pac::Peripherals::steal() }; - loop { - // Blink the red LED to indicate a panic - gpio2::set_out(&p.GPIO2, gpio2::GPIO2_CFG_LED0.pins); - for _ in 0..1_000_000 { - cortex_m::asm::nop(); - } - gpio2::clr_out(&p.GPIO2, gpio2::GPIO2_CFG_LED0.pins); - for _ in 0..1_000_000 { - cortex_m::asm::nop(); - } + unsafe { + asm!( + "1337:", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b", + "b 1337b" + ); } -} \ No newline at end of file + loop { } +} diff --git a/shell.nix b/shell.nix index 5879117..2f93329 100644 --- a/shell.nix +++ b/shell.nix @@ -1,16 +1,3 @@ -/** - * @file "shell.nix" - * @author Ben Janis - * @brief Nix shell environment file - * @date 2024 - * - * This source file is part of an example system for MITRE's 2024 Embedded System CTF (eCTF). - * This code is being provided only for educational purposes for the 2024 MITRE eCTF competition, - * and may not meet MITRE standards for quality. Use this code at your own risk! - * - * @copyright Copyright (c) 2024 The MITRE Corporation - */ - { pkgs ? import {} , fetchzip ? pkgs.fetchzip , fetchgit ? pkgs.fetchgit @@ -28,8 +15,12 @@ pkgs.mkShell { pkgs.gcc-arm-embedded pkgs.poetry pkgs.cacert + pkgs.pandoc + pkgs.nodejs + pkgs.tectonic + pkgs.haskellPackages.pandoc-crossref + pkgs.mermaid-filter #(pkgs.callPackage custom_nix_pkgs/analog_openocd.nix { }) - pkgs.minicom ]; LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";