Skip to content

Commit 71792e8

Browse files
authored
Merge pull request #62 from danielinux/ext_flash_encryption
External flash encryption
2 parents 938919e + 50456e2 commit 71792e8

30 files changed

Lines changed: 959 additions & 64 deletions

.gdbinit

Lines changed: 0 additions & 3 deletions
This file was deleted.

Makefile

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ ifeq ($(UART_FLASH),1)
125125
EXT_FLASH=1
126126
endif
127127

128+
ifeq ($(ENCRYPT),1)
129+
CFLAGS+=-DEXT_ENCRYPTED=1
130+
WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/chacha.o
131+
endif
132+
128133
ifeq ($(EXT_FLASH),1)
129134
CFLAGS+= -DEXT_FLASH=1 -DPART_UPDATE_EXT=1 -DPART_SWAP_EXT=1
130135
ifeq ($(NO_XIP),1)
@@ -179,8 +184,7 @@ ifeq ($(WOLFTPM),1)
179184
OBJS += lib/wolfTPM/src/tpm2.o \
180185
lib/wolfTPM/src/tpm2_packet.o \
181186
lib/wolfTPM/src/tpm2_tis.o \
182-
lib/wolfTPM/src/tpm2_wrap.o \
183-
hal/spi/spi_drv_$(SPI_TARGET).o
187+
lib/wolfTPM/src/tpm2_wrap.o
184188
CFLAGS+=-DWOLFBOOT_TPM -DSIZEOF_LONG=4 -Ilib/wolfTPM \
185189
-DMAX_COMMAND_SIZE=1024 -DMAX_RESPONSE_SIZE=1024 -DWOLFTPM2_MAX_BUFFER=1500 \
186190
-DMAX_SESSION_NUM=1 -DMAX_DIGEST_BUFFER=973 \
@@ -189,6 +193,9 @@ ifeq ($(WOLFTPM),1)
189193
CFLAGS+=-DWOLFTPM_SLB9670
190194
# Use TPM for hashing (slow)
191195
#CFLAGS+=-DWOLFBOOT_HASH_TPM
196+
ifneq ($(SPI_FLASH),1)
197+
WOLFCRYPT_OBJS+=hal/spi/spi_drv_$(SPI_TARGET).o
198+
endif
192199
endif
193200
OBJS+=$(WOLFCRYPT_OBJS)
194201

@@ -232,6 +239,7 @@ standalone:
232239
$(Q)$(SIZE) test-app/image.elf
233240

234241
include tools/test.mk
242+
include tools/test-enc.mk
235243

236244
ed25519.der:
237245
@$(KEYGEN_TOOL) $(KEYGEN_OPTIONS) src/ed25519_pub_key.c
@@ -303,6 +311,10 @@ include/target.h: include/target.h.in FORCE
303311
config: FORCE
304312
make -C config
305313

314+
../src/libwolfboot.o: ../src/libwolfboot.c FORCE
315+
@echo "\t[CC-$(ARCH)] $@"
316+
$(Q)$(CC) $(CFLAGS) -c -o $@ ../src/libwolfboot.c
317+
306318
%.o:%.c
307319
@echo "\t[CC-$(ARCH)] $@"
308320
$(Q)$(CC) $(CFLAGS) -c -o $@ $^

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ For detailed information about the configuration options for the target system,
8181

8282
For more detailed information about firmware update implementation, see [Firmware Update](docs/firmware_update.md)
8383

84+
85+
### Additional features
86+
- [Remote external flash interface](docs/remote_flash.md)
87+
- [External encrypted partitions](docs/encrypted_partitions.md)
88+
8489
## Troubleshooting
8590

8691
1. Python errors when signing a key:
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
ARCH?=ARM
2+
TARGET?=stm32wb
3+
SIGN?=ECC256
4+
HASH?=SHA256
5+
DEBUG?=0
6+
VTOR?=1
7+
CORTEX_M0?=0
8+
NO_ASM?=0
9+
EXT_FLASH?=1
10+
SPI_FLASH?=0
11+
NO_XIP?=0
12+
UART_FLASH?=1
13+
ALLOW_DOWNGRADE?=0
14+
NVM_FLASH_WRITEONCE?=1
15+
WOLFBOOT_VERSION?=0
16+
V?=0
17+
NO_MPU?=0
18+
SPMATH?=1
19+
RAM_CODE?=0
20+
DUALBANK_SWAP?=0
21+
IMAGE_HEADER_SIZE?=256
22+
PKA?=0
23+
ENCRYPT=1
24+
WOLFTPM?=0
25+
WOLFBOOT_PARTITION_SIZE?=0x20000
26+
WOLFBOOT_SECTOR_SIZE?=0x1000
27+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08010000
28+
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0
29+
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20000

docs/encrypted_partitions.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
## Encrypted external partitions
2+
3+
wolfBoot offers the possibility to encrypt the content of the entire UPDATE partition,
4+
by using a pre-shared symmetric key which can be temporarily stored in a safer non-volatile memory area.
5+
6+
SWAP partition is also temporarily encrypted using the same key, so a dump of the external flash won't reveal
7+
any content of the firmware update packages.
8+
9+
### Rationale
10+
11+
Encryption of external partition works at the level of the external flash interface.
12+
13+
All write calls to external partitions from the bootloader perform an additional encryption step
14+
to hide the actual content of the external non-volatile memory.
15+
16+
Viceversa, all read operations will decrypt the data stored when the feature is enabled.
17+
18+
An extra option is provided to the `sign.py` sign tool to encrypt the firmware update after signing it, so
19+
that it can be stored as is in the external memory by the application, and will be decrypted by the bootloader
20+
in order to verify the update and begin the installation.
21+
22+
23+
### Temporary key storage
24+
25+
By default, wolfBoot will store the pre-shared symmetric key used for encryption in a temporary area
26+
on the internal flash. This allows read-out protections to be used to hide the temporary key.
27+
28+
Alternatively, more secure mechanisms are available to store the temporary key in a different key storage
29+
(e.g. using a hardware security module or a TPM device).
30+
31+
The temporary key can be set at run time by the application, and will be used exactly once by the bootloader
32+
to verify and install the next update. The key can be for example received from a back-end during the update
33+
process using secure communication, and set by the application, using `libwolfboot` API, to be used by
34+
wolfBoot upon next boot.
35+
36+
Aside from setting the temporary key, the update mechanism remains the same for distributing, uploading and
37+
installing firmware updates through wolfBoot.
38+
39+
### Libwolfboot API
40+
41+
The API to communicate with the bootloader from the application is expanded when this feature is enabled,
42+
to allow setting a temporary key to process the next update.
43+
44+
The functions
45+
46+
```
47+
int wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce);
48+
int wolfBoot_erase_encrypt_key(void);
49+
```
50+
51+
can be used to set a temporary encryption key for the external partition, or erase a key previously set, respectively.
52+
53+
Moreover, using `libwolfboot` to access the external flash with wolfboot hal from the application will not
54+
use encryption. This way the received update, already encrypted at origin, can be stored in the external
55+
memory unchanged, and retrieved in its encrypted format, e.g. to verify that the transfer has been successful before
56+
reboot.
57+
58+
### Symmetric encryption algorithm
59+
60+
The algorithm currently used to encrypt and decrypt data in external partitions
61+
is Chacha20-256.
62+
63+
- The `key` provided to `wolfBoot_set_encrypt_key()` must be exactly 32 Bytes long.
64+
- The `nonce` argument must be a 96-bit (12 Bytes) randomly generated buffer, to be used as IV for encryption and decryption.
65+
66+
## Example usage
67+
68+
### Signing and encrypting the update bundle
69+
70+
The `sign.py` tool can sign and encrypt the image with a single command.
71+
The encryption secret is provided in a binary file that should contain a concatenation of
72+
a 32B ChaCha-256 key and a 12B nonce.
73+
74+
In the examples provided, the test application uses the following parameters:
75+
76+
```
77+
key = "0123456789abcdef0123456789abcdef"
78+
nonce = "0123456789ab"
79+
```
80+
81+
So it is easy to prepare the encryption secret in the test scripts or from the command line using:
82+
83+
```
84+
echo -n "0123456789abcdef0123456789abcdef0123456789ab" > enc_key.der
85+
```
86+
87+
The `sign.py` script can now be invoked to produce a signed+encrypted image, by using the extra argument `--encrypt` followed by the
88+
secret file:
89+
90+
```
91+
./tools/keytools/sign.py --encrypt enc_key.der test-app/image.bin ecc256.der 24
92+
93+
```
94+
95+
which will produce as output the file `test-app/image_v24_signed_and_encrypted.bin`, that can be transferred to the target's external device.
96+
97+
98+
### API usage in the application
99+
100+
When transferring the image, the application can still use the libwolfboot API functions to store the encrypted firmware. When called from the application,
101+
the function `ext_flash_write` will store the payload unencrypted.
102+
103+
In order to trigger an update, before calling `wolfBoot_update_trigger` it is necessary to set the temporary key used by the bootloader by calling `wolfBoot_set_encrypt_key`.
104+
105+
An example of encrypted update trigger can be found in the [stm32wb test application source code](test-app/app_stm32wb.c).
106+
107+
108+
109+

docs/remote_flash.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
## Remote External flash memory support via UART
2+
3+
wolfBoot can emulate external partitions using UART communication with a neighbor system. This feature
4+
is particularly useful in those asynchronous multi-process architectures, where updates can be stored
5+
with the assistance of an external processing unit.
6+
7+
### Bootloader setup
8+
9+
The option to activate this feature is `UART_FLASH=1`. This configuration option depends on the
10+
external flash API, which means that the option `EXT_FLASH=1` is also mandatory to compile the bootloader.
11+
12+
The HAL of the target system must be expanded to include a simple UART driver, that will be used by the
13+
bootloader to access the content of the remote flash using one of the UART controllers on board.
14+
15+
Example UART drivers for a few of the supported platforms can be found in the [hal/uart](hal/uart) directory.
16+
17+
The API exposed by the UART HAL extension for the supported targets is composed by the following functions:
18+
19+
```
20+
int uart_init(uint32_t bitrate, uint8_t data, char parity, uint8_t stop);
21+
int uart_tx(const uint8_t c);
22+
int uart_rx(uint8_t *c);
23+
```
24+
25+
Consider implementing these three functions based on the provided examples if you want to use external flash memory
26+
support on your platform, if not officially supported yet.
27+
28+
29+
### Host side: UART flash server
30+
31+
On the remote system hosting the external partition image for the target, a simple protocol can be implemented
32+
on top of UART messages to serve flash-access specific calls.
33+
34+
An example uart-flash-server daemon, designed to run on a GNU/Linux host and emulate the external partition with
35+
a local file on the filesystem, is available in [tools/uart-flash-server](tools/uart-flash-server).
36+
37+
38+
### External flash update mechanism
39+
40+
wolfBoot treats external UPDATE and SWAP partitions in the same way as when they are mapped on a local SPI flash.
41+
Read and write operations are simply translated into remote procedure calls via UART, that can be interpreted by
42+
the remote application and provide read and write access to actual storage elements which would only be accessible
43+
by the host.
44+
45+
This means that after a successful update, a copy of the previous firmware will be stored in the remote partition to
46+
provide exactly the same update mechanism that is available in all the other use cases. The only difference consist
47+
in the way of accessing the physical storage area, but all the mechanisms at a higher level stay the same.
48+
49+
50+
51+

0 commit comments

Comments
 (0)