# Using One-Time Programmable (OTP) flash area for keystore Some microcontrollers provide a special area in flash memory that can only be written once and cannot be erased. This feature comes particularly handy when you want to store the public keys required to authenticate the firmware update images, which has exactly the same requirements. A public key is a cryptographic key that can be freely distributed and is used to verify the signature of the firmware update image. By storing the public keys in the OTP area, you can ensure that they are immutable and cannot be tampered with. ## Compiling wolfBoot to access OTP as keystore To use the OTP area as a keystore, you need to compile wolfBoot with the `FLASH_OTP_KEYSTORE` option enabled. This option is disabled by default, which means that the keystore is incorporated into the wolfBoot binary itself. When wolfBoot uses the OTP area as a keystore, it reads the public keys from the OTP area at runtime. The public keys are stored in the OTP area, after an initial 16-byte header that contains the number of keys stored, the size of each key, and other information. In order for wolfBoot to start authenticating the firmware images at boot and upon update, the public keys must be provisioned to the OTP area in a separate step, as described in the next sections. Depending on the target device, you can either prepare a binary image of the OTP area content, or use `otp-keystore-primer` firmware to directly provision the keys on the target. ## Creating an image of the OTP area content It is possible to create a binary image of the content for the OTP area. The resulting file (otp.bin) can be manually provisioned using any external tool that allows writing to the target OTP area. To compile the otp-keystore-gen tool using the current keystore content: ```sh make otpgen ``` And then, to create the image file `otp.bin`: ```sh ./tools/keytools/otp/otp-keystore-gen ``` ## Directly provisioning the public keys to the OTP area (primer) After enabling the `FLASH_OTP_KEYSTORE` option in your `.config` file, when you compile wolfBoot by running "make", an additional application called `otp-keystore-primer` is generated under `tools/keytools/otp`. This application is used to provision the public keys to the OTP area. By flashing this application to the microcontroller, the public keys contained in your keystore (previously generated by `keygen`) are written to the OTP area. The `otp-keystore-primer` application is generated with the public keys embedded in it. The keys are retrieved from the `keystore.c` file, generated by the `keygen` command. The `otp-keystore-primer` application reads the public keys from the `keystore.c` file and writes them to the OTP area. After generating a new `keystore.c` with the `keygen` application, you can generate the `otp-keystore-primer` application again, by running `make otp`. > [!WARNING] > The `otp-keystore-primer` application is a one-time use application. Once the application runs on your target, the public keys are written to the OTP area, > and it will be impossible to erase them. Therefore, it is important to ensure that the public keys are correct before provisioning them to the OTP area, > and that the associated private keys are stored securely. Accidentally losing the private keys will render the public keys stored in the OTP area useless. > [!CAUTION] > ** Be very careful when using the `otp-keystore-primer` application. Use it at your own risk. ** ## Examples ### STM32H5 OTP KeyStore Example for NULCLEO-STM32H563ZI with TrustZone (via PKCS11), DualBank and signing with PQ LMS: 1) Setup the configuration and key tools: ```sh cp config/examples/stm32h5-tz-dualbank-otp-lms.config .config make include/target.h make keytools ``` 2) Generate key(s) to write to OTP - `./examples/keytools/keygen --lms -g 1.key -g 2.key -g 3.key -g 4.key -g 5.key` 3) Backup the generated keys and `src/keystore.c` - Save to safe place outside of the wolfBoot tree 4) Set the signing key to use - Copy one of the generated keys to `wolfboot_signing_private_key.der` - `cp 1.key wolfboot_signing_private_key.der` 5) Setup the OTP keystore Flash the OTP keystore primer: - Run `make otp` - Flash `./tools/keytools/otp/otp-keystore-primer.bin` to `0x08000000` - Disconnect the tool and hit reset button - The primer will run and flash keystore.c to OTP and enable write protection on those blocks OR Generate OTP (otp.bin) and flash using external tool - Run `make otpgen` - Run `./tools/keytools/otp/otp-keystore-gen` to generate an otp.bin file - Program otp.bin to `0x08FFF000` using external tool like STM32CubeProgrammer 6) Verify OTP keystore - Read memory at address `0x08FFF000` (should start with ASCII "WOLFBOOT") - Typically use STM32CubeProgrammer for this 7) Setup the option bytes - User Configuration 2 -> TrustZone Enable (TZEN=0xB4) - Bank1 - Flash Watermark area (SECWM1_START=0x00, SECWM1_END=0x1F) - Bank2 - Flash Watermark area (SECWM2_START=0x00, SECWM2_END=0x1F) 8) Mass erase the device - STM32CubeProgrammer -> Full chip erase 9) Build wolfBoot and test application using `make` 10) Flash wolfBoot and test-app - Flash `wolfboot.bin` at `0x0C000000` - Flash `test-app/image_v1_signed.bin` at `0x08040000` 11) Disconnect and reboot, the red LED should turn on. 12) Connect to USB UART on NUCLEO board for console Explore the command line (run help) ```sh ======================== STM32H5 wolfBoot demo Application Copyright 2024 wolfSSL Inc GPL v3 Version : 0x1 ======================== cmd> help help : shows this help message info : display information about the system and partitions success : confirm a successful update pkcs11 : enable and test crypto calls with PKCS11 in secure mode random : generate a random number timestamp : print the current timestamp benchmark : run the wolfCrypt benchmark test : run the wolfCrypt test update : update the firmware via XMODEM reboot : reboot the system ``` 13) Test Update - Sign a new version of the firmware: `./tools/keytools/sign --lms test-app/image.bin wolfboot_signing_private_key.der 2` - Run "update" command on the shell and wait for xmodem transfer - Use serial terminal that supports xmodem like "minicom" or "CoolTerm". * Run `minicom` on `/dev/ttyACM0` and start file transfer using "CTRL+A; S" * Select xmodem then navigate to the new signed firmware file `test-app/image_v2_signed.bin` - During the transfer, the yellow LED will flash. - The green LED is dim because it's sync with the UART RX - At the end of the transfer, the new image will be in the update partition. - Reset board to install new firmware and confirm new version number. Example update output: ```sh cmd> update Erasing update partition...Done. Waiting for XMODEM transfer... ....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... End of transfer. ret: 0 New firmware version: 0x2 Triggering update... Update completed successfully. cmd> reboot ======================== STM32H5 wolfBoot demo Application Copyright 2024 wolfSSL Inc GPL v3 Version : 0x2 ======================== cmd> ```