tillitis-key/hw/application_fpga
Michael Cardell Widerkrantz 9f975bb66f
Add clangd target
Create a compile_commands.json to help clangd for LSP.
2024-11-15 15:01:31 +01:00
..
core doc: Harmonize preformatted in tk1 core 2024-11-15 15:01:31 +01:00
data A construction of a minimal SPI master. 2024-06-11 15:28:29 +02:00
fw Harmonize the naming of firmware and app mode. 2024-11-12 15:13:59 +01:00
rtl Change "rosc" references to "trng" 2024-11-14 16:35:51 +01:00
tb Rename top level simulation files 2024-11-12 15:33:33 +01:00
tools Add place and route script 2024-10-22 15:20:39 +02:00
application_fpga.bin.sha256 Updated application_fpga.bin.sha256 with new hash 2024-11-14 16:35:51 +01:00
config.vlt Config verilator lint to ignore known 3rd-party warnings; let warnings be fatal 2023-03-01 13:37:31 +01:00
firmware.bin.sha512 FPGA: Move RAM address and data scrambling into the RAM module. 2024-08-30 10:53:13 +02:00
Makefile Add clangd target 2024-11-15 15:01:31 +01:00
README.md Move high level system description to README in application_fpga 2024-11-15 15:01:31 +01:00

System Description

NOTE: Documentation migrated to dev.tillitis.se, this is kept for history. This is likely to be outdated.

Purpose and Revision

The purpose of this document is to provide a description of the Tillitis TKey. What it is, what is supposed to be used for, by whom, where and possible use cases. The document also provides a functional level description of features and components of the TKey.

Finally, the document acts as a requirement description. For the requirements, the document follows RFC2119 to indicate requirement levels.

The described functionality and requirements applies to version 1 of the TKey (TK1)

The intended users of this document are:

  • Implementors of the TKey hardware, firmware and SDKs
  • Developers of secure applications for the TKey
  • Technically skilled third parties that wants to understand the TKey

Introduction

The TKey is a USB-connected, RISC-V based application platform. The purpose of the TKey is to provide a secure environment for TKey device apps that provides some security functionality to the client as needed by the use case and device user. Some examples of such security functionality are:

  • TOTP token generators
  • Signing oracles
  • SSH login dongles

TKey Security Features

Measured Based Security

The key, unique feature of the TKey is that it measures the secure application when the application is being loaded onto the device. The measurement (a hash digest), combined with a Unique Device Secret (UDS) is used to derive a base secret for the application.

The consequence of this is that if the application is altered, the base secret derived will also change. Conversely, if the keys derived from the base secret are the same as the last time the application was loaded onto the same device, the application can be trusted not to have been altered.

Note that since the UDS is per-device unique, the same application loaded onto another TKey device will derive a different set of keys. This ties keys to a specific device.

The derivation can also be combined with a User Supplied Secret (USS). This means that keys derived are both based on something the user has - the specific device, and something the user knows (the USS). And the derived can be trusted because of the measurement being used by the derivation, thereby verifying the integrity of the application.

Execution monitor

The purpose of the The Tillitis TKey execution monitor is to ensure that execution of instructions does not happen from memory areas containing application data och the stack.

The monitor continuously observes the address from which the CPU wants to fetch the next instruction. If that address falls within a defined address range from which execution is not allowed, the monitor will force the CPU to read an illegal instruction. This will cause the CPU to enter its trap state. There is no way out of this state, and the user must perform a power cycle of the TKey device.

Currently the following rules are implemented by the execution monitor (future releases may add more rules):

  • Execution from the firmware RAM (fw_ram) is always blocked by the monitor
  • Applications can define the area within RAM from which execution should be blocked

The application can define its no execution area to the ADDR_CPU_MON_FIRST and ADDR_CPU_MON_LAST registers in the tk1 core. When the registers have been set the application can enable the monitor for the area by writing to the ADDR_CPU_MON_CTRL register. Note that once the monitor has been enabled it can't be disabled and the addresses defining the area can't be changed.

Illegal instruction monitor

Execution of illegal instructions will cause the CPU to enter its trap state from which it can't exit. The hardware in the TKey will monitor the CPU state. If the CPU enters the trap state, the hardware will start flashing the RED led, signalling that the TKey is stuck in an error state.

RAM memory protection

The TKey hardware includes a simple form of RAM memory protection. The purpose of the RAM memory protection is to make it somewhat harder and more time consuming to extract application assets by dumping the RAM contents from a TKey device. The memory protection is not based on encryption and should not be confused with real encryption. The protection is randomised between power cycles. The randomisation should make it infeasible to improve asset extraction by observing multiple memory dumps from the same TKey device. The attack should also not directly scale to multiple TKey devices.

The memory protection is based on two separate mechanisms:

  1. Address randomisation
  2. Address dependent data randomization

The address randomization is implemented by XORing the CPU address with the contents of the ADDR_RAM_ADDR_RAND register in the tk1 core. The result is used as the RAM address

The data randomization is implemented by XORing the data written to the RAM with the contents of the ADDR_RAM_DATA_RAND register in the tk1 core as well as XORing with the CPU address. This means that the same data written to two different addresses will be scrambled differently. The same pair or XOR operations is also performed on the data read out from the RAM.

The memory protection is setup by the firmware. Access to the memory protection controls is disabled for applications. Before the memory protecetion is enabled, the RAM is filled with randomised data using Xorwow. So during boot the firmware perform the following steps to setup the memory protection:

  1. Get a random 32-bit value from the TRNG to use as data state for Xorwow.
  2. Get a random 32-bit value from the TRNG to use as accumulator for Xorwow.
  3. Fill RAM with a random sequence of values by writing to all RAM addresses. For each address use Xorwow to generate a new state, using the accumulator.
  4. Write a random 32-bit value from the TRNG into the ADDR_RAM_ADDR_RAND register.
  5. Write a random 32-bit value from the TRNG into the ADDR_RAM_DATA_RAND register.
  6. Receive the application sent from the client and write it in sequence into RAM.

Future TKey devices may implement a more secure ASLR mechanism, and use real encryption (for example PRINCE) for memory content protection. From the application point of view such a change will be transparent.

Assets

The TKey store and use the following assets internally:

  • UDS - Unique Device Secret. 256 bits. Provisioned and stored during device manufacturing. Never to be replaced during the life time of a given device. Used to derive application secrets. Must never leave the device. Tillitis will NOT store a copy of the UDS. Can be read by firmware once between power cycling

  • UDI - Unique Device ID. 64 bits. Provisioned and stored during device manufacturing. Only accessible by FW. Never to be replaced or altered during the life time of a given device. May be copied, extracted, read from the device.

  • CDI - Compound Device Identity. Computed by the FW when an application is loaded using the UDS and the application binary. Used by the application to derive secrets, keys as needed. The CDI should never be exposed.

Additionally the following asset could be provided from the host:

  • USS - User Supplied Secret. May possibly be replaced many times. Supplied from the host to the device. Should not be revealed to a third party.

Memory

Addressing:

31st bit                              0th bit
v                                     v
0000 0000 0000 0000 0000 0000 0000 0000

- Bits [31 .. 30] (2 bits): Top level prefix (described below)
- Bits [29 .. 24] (6 bits): Core select. We want to support at least 16 cores
- Bits [23 ..  0] (24 bits): Memory/in-core address.

Assigned top level prefixes:

name prefix address length
ROM 0b00 30 bit address
RAM 0b01 30 bit address
reserved 0b10
MMIO 0b11 6 bits for core select, 24 bits rest
memory first byte last byte
ROM 0x0000_0000 0x0000_17ff
RAM 0x4000_0000 0x4001_ffff
MMIO 0xc000_0000 0xffff_ffff (last possible)

Memory mapped hardware functions

Hardware functions, assets, and input/output are memory mapped (MMIO) starting at base address 0xc000_0000. For specific offsets/bitmasks, see the file tk1_mem.h (in this repo).

Assigned core prefixes:

name address prefix
TRNG 0xc0
TIMER 0xc1
UDS 0xc2
UART 0xc3
TOUCH 0xc4
FW_RAM 0xd0
TK1 0xff

Nota bene: MMIO accesses should be 32 bit wide, e.g use lw and sw. Exceptions are UDS, FW_RAM and QEMU_DEBUG.

name fw app size type content description
TRNG_STATUS r r TRNG_STATUS_READY_BIT is 1 when an entropy word is available.
TRNG_ENTROPY r r 4B u32 Entropy word. Reading a word will clear status.
TIMER_CTRL r/w r/w If TIMER_STATUS_RUNNING_BIT in TIMER_STATUS is 0, setting
TIMER_CTRL_START_BIT here starts the timer.
If TIMER_STATUS_RUNNING_BIT in TIMER_STATUS is 1, setting
TIMER_CTRL_STOP_BIT here stops the timer.
TIMER_STATUS r r TIMER_STATUS_RUNNING_BIT is 1 when the timer is running.
TIMER_PRESCALER r/w r/w 4B Prescaler init value. Write blocked when running.
TIMER_TIMER r/w r/w 4B Timer init or current value while running. Write blocked when running.
UDS_FIRST r1 invisible 4B u8[32] First word of Unique Device Secret key. Note: Read once per power up.
UDS_LAST invisible The last word of the UDS. Note: Read once per power up.
UART_BITRATE r/w TBD
UART_DATABITS r/w TBD
UART_STOPBITS r/w TBD
UART_RX_STATUS r r 1B u8 Non-zero when there is data to read
UART_RX_DATA r r 1B u8 Data to read. Only LSB contains data
UART_RX_BYTES r r 4B u32 Number of bytes received from the host and not yet read by SW, FW.
UART_TX_STATUS r r 1B u8 Non-zero when it's OK to write data to send.
UART_TX_DATA w w 1B u8 Data to send. Only LSB contains data
TOUCH_STATUS r/w r/w TOUCH_STATUS_EVENT_BIT is 1 when touched. After detecting a touch
event (reading a 1), write anything here to acknowledge it.
FW_RAM r/w invisible 2 kiB u8[2048] Firmware-only RAM.
UDI r invisible 8B u64 Unique Device ID (UDI).
QEMU_DEBUG w w u8 Debug console (only in QEMU)
NAME0 r r 4B char[4] "tk1 " ID of core/stick
NAME1 r r 4B char[4] "mkdf" ID of core/stick
VERSION r r 4B u32 1 Current version.
SYSTEM_MODE_CTRL r/w r 1B u8 Write anything here to trigger the switch to application mode. Reading
returns 0 if device is in firmware mode, 0xffffffff if in app mode.
LED r/w r/w 1B u8 Control of the color LEDs in RBG LED on the board.
Bit 0 is Blue, bit 1 is Green, and bit 2 is Red LED.
GPIO r/w r/w 1B u8 Bits 0 and 1 contain the input level of GPIO 1 and 2.
u8 Bits 3 and 4 store the output level of GPIO 3 and 4.
APP_ADDR r/w r 4B u32 Firmware stores app load address here, so app can read its own location
APP_SIZE r/w r 4B u32 Firmware stores app app size here, so app can read its own size
BLAKE2S r/w r 4B u32 Function pointer to a BLAKE2S function in the firmware
CDI_FIRST r/w r 32B u8[32] Compound Device Identifier (CDI). UDS+measurement...
CDI_LAST r Last word of CDI
RAM_ASLR w invisible 4B u32 Address Space Randomization seed value for the RAM
RAM_SCRAMBLE w invisible 4B u32 Data scrambling seed value for the RAM
CPU_MON_CTRL w w 4B u32 Bit 0 enables CPU execution monitor. Can't be unset. Lock adresses
CPU_MON_FIRST w w 4B u32 First address of the area monitored for execution attempts
CPU_MON_LAST w w 4B u32 Last address of the area monitored for execution attempts

Subsystems and Components

The TKey as a project, system and secure application platform consists of a number of subsystems and components, modules, support libraries etc. Roughly these can be divided into:

  • TKey boards. PCB designs including schematics, Bill of Material (BOM) and layout, as needed for development, production and and general usage of the TKey devices

  • TKey programmer. SW, PCB designs including schematics, Bill of Material (BOM) and layout, as needed for development, production and and provisioning, programming general usage

  • USB to UART controller. FW for the MCU implementing the USB host interface on the TKey

  • application_fpga. FPGA design with cores including CPU and memory that implements the secure application platform

  • application_fpga FW. The base software running on the CPU as needed to boot, load applications, measure applications, dderive base secret etc

  • One or more applications loaded onto the application_fpga to provide some functionality to the user of the host

  • host side application loader. Software that talks to the FW in the application_fpga to load a secure application

  • host side boot, management. Support software to boot, authenticate the TKey device connected to a host

  • host side secure application. Software that communicates with the secure application running in the application_fpga as needed to solve a security objective

  • application_fpga FW SDK. Tools, libraries, documentation and examples to support development of the application_fpga firmware

  • secure application SDK. Tools, libraries, documentation and examples to support development of the secure applications to be loaded onto the application_fpga

  • host side secure application SDK. Tools, libraries, documentation and examples to support development of the host applications

References

More detailed information about the firmware running on the device can be found in the hw/application_fpga/fw/README.md.


  1. The UDS can only be read once per power-cycle. ↩︎