mirror of https://github.com/wolfSSL/wolfBoot.git
Compare commits
39 Commits
Author | SHA1 | Date |
---|---|---|
|
dea8b4e347 | |
|
dd03cf19c4 | |
|
79cef5f605 | |
|
b79be86a56 | |
|
bd179ed339 | |
|
566f3b99cb | |
|
708b797c8f | |
|
3d9beb2642 | |
|
2e5bbfe273 | |
|
b07d99b57e | |
|
7bc947dd06 | |
|
73fc193931 | |
|
844196981b | |
|
8e6b0af105 | |
|
476d1c834b | |
|
9451b47628 | |
|
4787d70cd8 | |
|
487efc606d | |
|
77ede65739 | |
|
28bf060488 | |
|
c90c01ac2d | |
|
b62ec9da33 | |
|
6e8870156e | |
|
e3c7f6c663 | |
|
1b9ec09b1a | |
|
16c160146f | |
|
2d6cf95c20 | |
|
4154057649 | |
|
0bf65fabb3 | |
|
6abf550754 | |
|
ac0eb6dd9f | |
|
d689656a71 | |
|
23cf367c38 | |
|
be9b21dddc | |
|
38d1441627 | |
|
7660bf66f8 | |
|
2b996f8280 | |
|
16e5b94e9d | |
|
d49e507926 |
|
@ -0,0 +1,21 @@
|
|||
name: Test PIC32CZ and PIC32CK Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'master', 'main', 'release/**' ]
|
||||
pull_request:
|
||||
branches: [ '*' ]
|
||||
|
||||
jobs:
|
||||
build-pic32cz:
|
||||
uses: ./.github/workflows/test-build.yml
|
||||
with:
|
||||
arch: ARM
|
||||
config-file: config/examples/pic32cz.config
|
||||
make-args: "TARGET=pic32cz"
|
||||
build-pic32ck:
|
||||
uses: ./.github/workflows/test-build.yml
|
||||
with:
|
||||
arch: ARM
|
||||
config-file: config/examples/pic32ck.config
|
||||
make-args: "TARGET=pic32ck"
|
|
@ -18,6 +18,8 @@ jobs:
|
|||
file: "config/examples/sim-wolfHSM.config"
|
||||
- name: "wolfHSM ML-DSA"
|
||||
file: "config/examples/sim-wolfHSM-mldsa.config"
|
||||
- name: "wolfHSM cert chain verify"
|
||||
file: "config/examples/sim-wolfHSM-certchain.config"
|
||||
fail-fast: false
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -54,8 +56,7 @@ jobs:
|
|||
with:
|
||||
repository: wolfssl/wolfHSM-examples
|
||||
# Make sure to update this when the wolfHSM submodule is updated!
|
||||
#ref: wolfHSM-v1.1.0
|
||||
ref: 3e03bd4d4a8439ed4a8a9577823c89e4c37eb9be
|
||||
ref: wolfHSM-examples-v1.2.0
|
||||
path: wolfHSM-examples
|
||||
|
||||
- name: Build example POSIX TCP server
|
||||
|
@ -65,7 +66,13 @@ jobs:
|
|||
- name: Run POSIX TCP server
|
||||
run: |
|
||||
cd wolfHSM-examples/posix/tcp/wh_server_tcp
|
||||
./Build/wh_server_tcp.elf --client 12 --id 255 --key ../../../../wolfboot_signing_private_key_pub.der &
|
||||
if [ "${{ matrix.config.name }}" = "wolfHSM cert chain verify" ]; then
|
||||
tmpfile=$(mktemp)
|
||||
echo "obj 1 0xFFFF 0x0000 \"cert CA\" ../../../../test-dummy-ca/root-cert.der" >> $tmpfile
|
||||
./Build/wh_server_tcp.elf --nvminit $tmpfile &
|
||||
else
|
||||
./Build/wh_server_tcp.elf --client 12 --id 255 --key ../../../../wolfboot_signing_private_key_pub.der &
|
||||
fi
|
||||
TCP_SERVER_PID=$!
|
||||
echo "TCP_SERVER_PID=$TCP_SERVER_PID" >> $GITHUB_ENV
|
||||
|
||||
|
|
|
@ -61,8 +61,8 @@ src/ecc512_pub_key.c
|
|||
src/rsa2048_pub_key.c
|
||||
src/rsa4096_pub_key.c
|
||||
# Renesas key data files
|
||||
include/key_data.c
|
||||
include/key_data.h
|
||||
include/key_data.*
|
||||
include/enckey_data.*
|
||||
|
||||
# keygen binaries
|
||||
tools/keytools/sign
|
||||
|
@ -99,6 +99,7 @@ include/target.h
|
|||
.wolfboot-partition-size
|
||||
.bootloader-partition-size
|
||||
MPLabX/wolfBoot-SAME51.X/.generated_files/
|
||||
test-dummy-ca/**
|
||||
|
||||
# Test tools
|
||||
tools/check_config/check_config
|
||||
|
@ -118,7 +119,13 @@ tools/tpm/policy_sign
|
|||
config/*.ld
|
||||
test-lib
|
||||
|
||||
# Generated configuration file
|
||||
# Elf preprocessing tools
|
||||
tools/squashelf/**
|
||||
!tools/squashelf/squashelf.c
|
||||
!tools/squashelf/Makefile
|
||||
!tools/squashelf/README.md
|
||||
|
||||
# Generated configuration files
|
||||
.config
|
||||
.vs
|
||||
*.filters
|
||||
|
@ -247,3 +254,4 @@ lib/r_tsip_rx
|
|||
|
||||
Debug/
|
||||
Release/
|
||||
language.settings.xml
|
||||
|
|
|
@ -8,9 +8,13 @@ This example demonstrates using wolfBoot on the Infineon AURIX TC3xx family of m
|
|||
- [Overview](#overview)
|
||||
- [Important notes](#important-notes)
|
||||
- [Flash Partitioning](#flash-partitioning)
|
||||
- [Standard wolfBoot images](#standard-wolfboot-images)
|
||||
- [ELF files](#elf-files)
|
||||
- [Cert Chain Verification](#cert-chain-verification)
|
||||
- [Configuration and the wolfBoot AURIX tool (wbaurixtool.sh)](#configuration-and-the-wolfboot-aurix-tool-wbaurixtoolsh)
|
||||
- [Building and running the wolfBoot demo](#building-and-running-the-wolfboot-demo)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Important notes](#important-notes-1)
|
||||
- [Clone wolfBoot](#clone-wolfboot)
|
||||
- [Build wolfBoot keytools and generate keys](#build-wolfboot-keytools-and-generate-keys)
|
||||
- [Install the Infineon TC3xx SDK into the wolfBoot project](#install-the-infineon-tc3xx-sdk-into-the-wolfboot-project)
|
||||
|
@ -20,13 +24,18 @@ This example demonstrates using wolfBoot on the Infineon AURIX TC3xx family of m
|
|||
- [Load and run the wolfBoot demo in TRACE32](#load-and-run-the-wolfboot-demo-in-trace32)
|
||||
- [wolfHSM Compatibility](#wolfhsm-compatibility)
|
||||
- [Building wolfBoot with wolfHSM](#building-wolfboot-with-wolfhsm)
|
||||
- [Building wolfBoot with wolfHSM and cert chain verification](#building-wolfboot-with-wolfhsm-and-cert-chain-verification)
|
||||
- [Custom Certificate Chain](#custom-certificate-chain)
|
||||
- [Dummy Certificate Chain](#dummy-certificate-chain)
|
||||
- [Building: Command Sequence](#building-command-sequence)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [WSL "bad interpreter" error](#wsl-bad-interpreter-error)
|
||||
- [Post Quantum: ML-DSA](#post-quantum-ml-dsa)
|
||||
- [ML-DSA Keytools](#ml-dsa-keytools)
|
||||
|
||||
The example contains two projects: `wolfBoot-tc3xx` and `test-app`. The `wolfBoot-tc3xx` project contains the wolfBoot bootloader, and the `test-app` project contains a simple firmware application that will be loaded and executed by wolfBoot. The `test-app` project is a simple blinky application that blinks LED2 on the TC375 Lite-Kit V2 once per second when running the base image, and rapidly (~3x/sec) when running the update image. The test app determines if it is a base or update image by inspecting the firmware version (obtained through the wolfBoot API). The firmware version is set in the image header by the wolfBoot keytools when signing the test app binaries. The same test app binary is used for both the base and update images, with the only difference being the firmware version set by the keytools.
|
||||
The example contains two projects: `wolfBoot-tc3xx` and `test-app`. The `wolfBoot-tc3xx` project contains the wolfBoot bootloader, and the `test-app` project contains a simple firmware application that will be loaded and executed by wolfBoot. The `test-app` project is a simple blinky application that blinks LED1 on the TC375 Lite-Kit V2 once per second when running the base image, and rapidly (~3x/sec) when running the update image. The test app determines if it is a base or update image by inspecting the firmware version (obtained through the wolfBoot API). The firmware version is set in the image header by the wolfBoot keytools when signing the test app binaries. The same test app binary is used for both the base and update images, with the only difference being the firmware version set by the keytools.
|
||||
|
||||
This example supports loading the test application firmware as standard wolfBoot images or as an ELF file. Refer to the [firmware_update.md](../docs/firmware_update.md) documentation for more information on how the wolfBoot flash loader supports loading ELF files.
|
||||
|
||||
## Important notes
|
||||
|
||||
|
@ -34,10 +43,15 @@ The example contains two projects: `wolfBoot-tc3xx` and `test-app`. The `wolfBoo
|
|||
- Because TC3xx PFLASH ECC prevents reading from erased flash, the `EXT_FLASH` option is used to redirect flash reads to the `ext_flash_read()` HAL API, where the flash pages requested to be read can be blank-checked by hardware before reading.
|
||||
- TC3xx PFLASH is write-once (`NVM_FLASH_WRITEONCE`), however wolfBoot `NVM_FLASH_WRITEONCE` does not support `EXT_FLASH`. Therefore the write-once functionality is re-implemented in the `HAL` layer.
|
||||
- This demo app is only compatible with the GCC toolchain build configurations shipped with the AURIX IDE. The TASKING compiler build configurations are not yet supported.
|
||||
- When detailing commands to be run, square brackets `[]` are used to indicate optional arguments. Do not include the square brackets when running the commands.
|
||||
|
||||
## Flash Partitioning
|
||||
|
||||
The TC3xx AURIX port of wolfBoot places all images in PFLASH, and uses both PFLASH0 and PFLASH1 banks. The wolfBoot executable code and the image swap sector are located in PFLASH0, with the remainder available for use. PFLASH1 is divided in half, with the first half holding the BOOT partition and the second half holding the UPDATE partition. User firmware images are directly executed in place from the BOOT partition in PFLASH1, and so must be linked to execute within this address space, with an offset of `IMAGE_HEADER_SIZE` to account for the wolfBoot image header.
|
||||
The TC3xx AURIX port of wolfBoot places all images in PFLASH, and uses both PFLASH0 and PFLASH1 banks. The wolfBoot executable code and the image swap sector are located in PFLASH0, with the remainder available for use. The layout of PFLASH1 depends on whether the test application is being loaded as a standard wolfBoot image or an ELF file.
|
||||
|
||||
### Standard wolfBoot images
|
||||
|
||||
When configured to load standard wolfBoot images, the demo application divides PFLASH1 approximately in half, with the first half holding the BOOT partition and the second half holding the UPDATE partition. User firmware images are directly executed in place from the BOOT partition in PFLASH1, and so must be linked to execute within this address space, with an offset of `IMAGE_HEADER_SIZE` to account for the wolfBoot image header. The last sector of PFLASH1 is reserved for the SWAP area.
|
||||
|
||||
```
|
||||
+==========+
|
||||
|
@ -61,11 +75,37 @@ The TC3xx AURIX port of wolfBoot places all images in PFLASH, and uses both PFLA
|
|||
+----------+ <-- 0x8060_0000
|
||||
```
|
||||
|
||||
Please refer to the [wolfBoot](wolfBoot-tc3xx/Lcf_Gnu_Tricore_Tc.lsl.in) and [test-app](test-app/Lcf_Gnu_Tricore_Tc.lsl.in) linker script templates for the exact memory configuration.
|
||||
### ELF files
|
||||
|
||||
When loading the test app as an ELF file, PFLASH1 is divided into three sections. Approximately the first half of PFLASH1 is reserved for application use. This is the region that the application should be linked to execute from, and should contain all loadable segments in the ELF file. The second half of PFLASH1 is divided equally between the BOOT and UPDATE partitions as with standard wolfBoot images, with the last sector reserved for SWAP.
|
||||
|
||||
```
|
||||
+==========+
|
||||
| PFLASH1 |
|
||||
+==========+ <-- 0x8030_0000
|
||||
| APP | ~1.5M (0x17_C000)
|
||||
+----------+ <-- 0x8047_C000
|
||||
| BOOT | ~0.75M (0xC_0000)
|
||||
+----------+ <-- 0x8053_C000
|
||||
| UPDATE | ~0.75M (0xC_0000)
|
||||
+----------+ <-- 0x805F_C000
|
||||
| SWAP | 16K (0x4000)
|
||||
+----------+ <-- 0x8060_0000
|
||||
```
|
||||
|
||||
Different linker script templates are used to configure the memory layout via `wbaurixtool.sh` (see next section) depending on whether standard wolfBoot images or ELF files are being loaded. Please refer to the following linker script templates for the exact memory configuration:
|
||||
|
||||
- [wolfBoot](wolfBoot-tc3xx/Lcf_Gnu_Tricore_Tc.lsl.in)
|
||||
- [test-app (standard wolfBoot images)](test-app/Lcf_Gnu_Tricore_Tc.lsl.in)
|
||||
- [test-app (ELF files)](test-app/Lcf_Gnu_Tricore_elf.lsl.in)
|
||||
|
||||
### Cert Chain Verification
|
||||
|
||||
wolfBoot on AURIX supports verifying firmware images using certificate chains. For more information on how this wolfBoot feature works, refer to [Signing.md](../../docs/Signing.md), [firmware_update.md](../docs/firmware_update.md), and [wolfBoot-wolfHSM](../../IDE/AURIX/wolfBoot-wolfHSM). Currently this feature can only be used in conjunction with wolfHSM. Instructions for using this feature are detailed below in the [Building wolfBoot with wolfHSM](#building-wolfboot-with-wolfhsm) section.
|
||||
|
||||
## Configuration and the wolfBoot AURIX tool (wbaurixtool.sh)
|
||||
|
||||
wolfBoot relies extensively on its build system in order to properly set configuration macros, linker addresses, and other target-specific items. Because wolfBoot on AURIX uses the AURIX studio IDE to build, changing things like the signature algorithm would require manually editing IDE settings, linker scripts, etc. which is error prone and tedious. The `wbaurixtool.sh` script provides a single tool that automates the generation of all configurable items required for building wolfBoot and the test application on aurix given the chosen signature and hashing algorithms, including managing all configuration macros, linker scripts, as well as handling the actual key generation and image signing process. `wbaurixtool.sh` can also generate wolfHSM NVM images containing the generated image signing key when used in conjunction with wolfHSM.
|
||||
wolfBoot relies extensively on its build system in order to properly set configuration macros, linker addresses, and other target-specific items. Because wolfBoot on AURIX uses the AURIX studio IDE to build, changing things like the signature algorithm would require manually editing IDE settings, linker scripts, etc. which is error prone and tedious. The `wbaurixtool.sh` script provides a single tool that automates the generation of all configurable items required for building wolfBoot and the test application on AURIX given the chosen signature and hashing algorithms, including managing all configuration macros, linker scripts, as well as handling the actual key generation and image signing process. `wbaurixtool.sh` can also generate wolfHSM NVM images containing the generated image signing key when used in conjunction with wolfHSM.
|
||||
|
||||
The general usage of `wbaurixtool.sh` is as follows:
|
||||
|
||||
|
@ -73,7 +113,12 @@ The general usage of `wbaurixtool.sh` is as follows:
|
|||
$ ./wbaurixtool.sh [global options] <subcommand> [subcommand options]
|
||||
```
|
||||
|
||||
where `<subcommand>` is one of the following:
|
||||
where `[global options]` are:
|
||||
|
||||
- `--hsm`: Use the wolfHSM AURIX projects instead of the standard projects (e.g. `wolfBoot-tc3xx-wolfHSM` and `test-app-wolfHSM`)
|
||||
- `--elf`: loads the test application as an ELF file instead of the standard wolfBoot image. If you wish to load the test application as an ELF file, all invocations of `wbaurixtool.sh` must use the `--elf` option.
|
||||
|
||||
and where `<subcommand>` is one of the following:
|
||||
|
||||
- `keygen`: Generate a new signing key pair
|
||||
- `sign`: Sign a firmware image
|
||||
|
@ -99,6 +144,10 @@ For more information on the `wbaurixtool.sh` script, run `./wbaurixtool.sh --hel
|
|||
- A WSL2 distro (tested on Ubuntu 22.04) with the `build-essential` package installed (`sudo apt install build-essential`)
|
||||
- A TC375 AURIX Lite-Kit V2
|
||||
|
||||
### Important notes
|
||||
|
||||
- If you wish to load the test application as an ELF file, all invocations of `wbaurixtool.sh` must use the global `--elf` option before any subcommand. Otherwise, the invocation to `wbaurixtool.sh` will execute its commands as if the test application was a standard wolfBoot image. Mixing and matching `--elf` invocations with non-`--elf` invocations to `wbaurixtool.sh` will result in difficult to diagnose build or runtime errors. When in doubt, clean all build artifacts and start fresh.
|
||||
|
||||
### Clone wolfBoot
|
||||
|
||||
1. Clone the wolfBoot repository and initialize the repository submodules (`git submodule update --init`)
|
||||
|
@ -109,10 +158,10 @@ For more information on the `wbaurixtool.sh` script, run `./wbaurixtool.sh --hel
|
|||
2. Compile the keytools by running `make keytools`
|
||||
3. Use the helper script to generate a new signing key pair using ECC 256
|
||||
1. Navigate to `wolfBoot/tools/scripts/tc3xx`
|
||||
2. Run `./wbaurixtool.sh keygen --sign-algo ecc256 macros lcf`. This:
|
||||
2. Run `./wbaurixtool.sh [--elf] keygen --sign-algo ecc256 macros lcf`. This:
|
||||
- Generates the signing private key `wolfBoot/priv.der` and adds the public key to the wolfBoot keystore (see [keygen](https://github.com/wolfSSL/wolfBoot/blob/aurix-tc3xx-support/docs/Signing.md) for more information)
|
||||
- Generates the `wolfBoot_macros.txt` file from the `wolfBoot_macros.in` template in the `wolfBoot-tc3xx` directory, which sets the appropriate wolfBoot preprocessor macros based on the hash and signature algorithms. The `wolfBoot_macros.txt` file is then passed to the compiler in the AURIX project
|
||||
- Generates the `Lcf_Gnu_Tricore_Tc.lsl` file from the `Lcf_Gnu_Tricore_Tc.lcf.in` template in the `test-app` directory, which sets appropriate values for Linker addresses (e.g. wolfBoot header size)based on the selected signature algorithm. The `Lcf_Gnu_Tricore_Tc.lsl` file is then passed to the linker in the AURIX project
|
||||
- Generates the `Lcf_Gnu_Tricore_Tc.lsl` file from either the `Lcf_Gnu_Tricore_Tc.lcf.in` template in the `test-app` directory or the `Lcf_Gnu_Tricore_elf.lcf.in` template in the `test-app` directory, which sets appropriate values for Linker addresses (e.g. wolfBoot header size) based on the selected signature algorithm. The `Lcf_Gnu_Tricore_Tc.lsl` file is then passed to the linker in the AURIX project
|
||||
- Note that if you already have generated keys, you can use `./wbaurixtool.sh clean` to remove them first
|
||||
|
||||
```
|
||||
|
@ -164,7 +213,7 @@ wolfBoot/IDE/AURIX/Configurations/
|
|||
### Build wolfBoot
|
||||
1. Generate the 'target.h` header file for the tc375 flash configuration
|
||||
1. Open a WSL terminal and navigate to `wolfBoot/tools/scripts/tc3xx`
|
||||
2. Run `./wbaurixtool.sh target`
|
||||
2. Run `./wbaurixtool.sh [--elf] target`
|
||||
2. Open the AURIX IDE and create a new workspace directory, if you do not already have a workspace you wish to use
|
||||
3. Import the wolfBoot project
|
||||
1. Click "File" -> Open Projects From File System"
|
||||
|
@ -176,9 +225,10 @@ wolfBoot/IDE/AURIX/Configurations/
|
|||
3. Click the hammer icon to build the active project. This will compile wolfBoot.
|
||||
5. Import the test-app project using the same procedure as in step (3), except using `wolfBoot/IDE/AURIX/test-app` as the directory
|
||||
6. Build the test-app project using the same procedure as in step (4), except choosing the `test-app` eclipse project. Note that the build process contains a custom post-build step that converts the application `elf` file into a `.bin` file using `tricore-elf-objcopy`, which can then be signed by the wolfBoot key tools in the following step
|
||||
7. Sign the generated test-app binary using the wolfBoot keytools
|
||||
7. If intending to build and load elf files, compile the squashelf tool by running `make` in the `tools/squashelf` directory. This step can be skipped if you only wish to build and load standard wolfBoot images.
|
||||
8. Sign the generated test-app binary using the wolfBoot keytools
|
||||
1. Open a WSL terminal and navigate to `wolfBoot/tools/scripts/tc3xx`
|
||||
2. Run `./wbaurixtool.sh sign --debug` or `./wbaurixtool.sh sign` to sign either the debug or release build, respectively. This creates the signed image files `test-app_v1_signed.bin` and `test-app_v2_signed.bin` in the test-app output build directory. The v1 image is the initial image that will be loaded to the `BOOT` partition, and the v2 image is the update image that will be loaded to the `UPDATE` partition.
|
||||
2. Run `./wbaurixtool.sh [--elf] sign --debug` or `./wbaurixtool.sh [--elf] sign` to sign either the debug or release build, respectively. This creates the signed image files `test-app_v1_signed.bin` and `test-app_v2_signed.bin` in the test-app output build directory. The v1 image is the initial image that will be loaded to the `BOOT` partition, and the v2 image is the update image that will be loaded to the `UPDATE` partition. If `--elf` is specified, `wbaurixtool.sh` will first preprocess the test-app ELF file with [squashelf](../../tools/squashelf) and then sign the resulting ELF file which contains only loadable segments.
|
||||
|
||||
```
|
||||
$ ./wbaurixtool.sh sign
|
||||
|
@ -236,7 +286,7 @@ The device is now configured to boot from `0xA00A0000` out of reset.
|
|||
|
||||
We can now load wolfBoot and the firmware application images to the tc3xx device using Trace32 and a Lauterbach probe
|
||||
|
||||
1. Click "File" -> "ChangeDir and Run Script" and choose the `wolfBoot/tools/scripts/tc3xx/wolfBoot-loadAll-$BUILD.cmm` script, where $BUILD should be either "debug" or "release" depending on your build type in (4) and (6).
|
||||
1. Click "File" -> "ChangeDir and Run Script" and choose the `wolfBoot/tools/scripts/tc3xx/wolfBoot-loadAll-$BUILD.cmm` script, where $BUILD should be either "debug" or "release" depending on your build type from earlier. There are also corresponding ELF load scripts for loading the test app as an ELF image.
|
||||
|
||||
wolfBoot and the demo applications are now loaded into flash, and core0 will be halted at the wolfBoot entry point (`core0_main()`).
|
||||
|
||||
|
@ -275,8 +325,29 @@ IDE/AURIX/wolfHSM-infineon-tc3xx/
|
|||
4. Follow all of the steps in [Building and Running the wolfBoot Demo](#building-and-running-the-wolfboot-demo) for the non-HSM enabled case, but with the following key differences:
|
||||
1. The [wolfBoot-tc3xx-wolfHSM](./wolfBoot-tc3xx-wolfHSM/) AURIX Studio project should be used instead of `wolfBoot-tc3xx`
|
||||
2. Use the `wolfBoot-wolfHSM-loadAll-XXX.cmm` lauterbach scripts instead of `wolfBoot-loadAll-XXX.cmm` to load the wolfBoot and test-app images in the TRACE32 GUI
|
||||
3. Provide the `--hsm` global option to the `wbaurixtool.sh` script when invoking it, so the wolfHSM projects are used instead of the standard wolfBoot projects
|
||||
4. If using the default build options in [wolfBoot-tc3xx-wolfHSM](./wolfBoot-tc3xx-wolfHSM/), wolfBoot will expect the public key for image verification to be stored at a specific keyId for the wolfBoot client ID. You can use [whnvmtool](https://github.com/wolfSSL/wolfHSM/tree/main/tools/whnvmtool) to generate a loadable NVM image that contains the required keys automatically via `wbaurixtool.sh` through the `nvm` subcommand. This generates an NVM image containing the generated image signing key based on the [wolfBoot-wolfHSM-keys.nvminit](../../tools/scripts/tc3xx/wolfBoot-wolfHSM-keys.nvminit) configuration file, which can then be loaded to the device via a flash programming tool. See the `whnvmtool` documentation and the documentation included in your wolfHSM AURIX release for more details. Note: if you want to use the standard wolfBoot keystore functionality in conjunction with wolfHSM for testing purposes (doesn't require pre-loading keys on the HSM) you can configure wolfBoot to send the keys to the HSM on-the-fly as ephemeral keys. To do this, ensure `WOLFBOOT_USE_WOLFHSM_PUBKEY_ID` is **NOT** defined, and add the `--localkeys` argument to then `./wbaurixtool.sh keygen` command, which invokes the `keygen` tool without the default `--nolocalkeys` option.
|
||||
3. Provide the `--hsm` global option to the `wbaurixtool.sh` script when invoking it so that the wolfHSM projects are used instead of the standard wolfBoot projects
|
||||
4. If using the default build options in [wolfBoot-tc3xx-wolfHSM](./wolfBoot-tc3xx-wolfHSM/), wolfBoot will expect the public key for image verification to be stored at a specific keyId for the wolfBoot client ID. You can use [whnvmtool](https://github.com/wolfSSL/wolfHSM/tree/main/tools/whnvmtool) to generate a loadable NVM image that contains the required keys automatically via `wbaurixtool.sh` through the `nvm` subcommand. This generates an NVM image containing the generated image signing key based on the [wolfBoot-wolfHSM-keys.nvminit](../../tools/scripts/tc3xx/wolfBoot-wolfHSM-keys.nvminit) configuration file, which can then be loaded to the device via a flash programming tool. Before using the `nvm` subcommand of `wbaurixtool.sh`, first compile `whnvmtool` by running `make` in the `lib/wolfHSM/tools/whnvmtool` directory. See the `whnvmtool` documentation and the documentation included in your wolfHSM AURIX release for more details. Note: if you want to use the standard wolfBoot keystore functionality in conjunction with wolfHSM for testing purposes (doesn't require pre-loading keys on the HSM) you can configure wolfBoot to send the keys to the HSM on-the-fly as ephemeral keys. To do this, ensure `WOLFBOOT_USE_WOLFHSM_PUBKEY_ID` is **NOT** defined, and add the `--localkeys` argument to then `./wbaurixtool.sh keygen` command, which invokes the `keygen` tool without the default `--nolocalkeys` option.
|
||||
|
||||
### Building wolfBoot with wolfHSM and cert chain verification
|
||||
|
||||
wolfBoot with wolfHSM supports certificate chain verification for firmware images. This feature allows wolfBoot to verify that firmware images are signed with certificates that can be traced back to a trusted root certificate authority through a certificate chain.
|
||||
|
||||
The `wbaurixtool.sh` script provides two options for applicable commands that enable automation of configuring the build for certificate chain verification:
|
||||
|
||||
- `--certchain <file>`: Use a user-provided certificate chain file
|
||||
- `--dummy-certchain`: Use a "dummy" certificate chain that is created from the key pair generated by the wolfBoot keytools for development/testing purposes.
|
||||
|
||||
Both options require the `--hsm` global option and can be used with the `keygen`, `sign`, `macros`, `lcf`, and `nvm` subcommands.
|
||||
|
||||
### Custom Certificate Chain
|
||||
|
||||
If you want to use a custom certificate chain for verification, you can provide the `--certchain <certchain file>` option to the `macros`, `lcf`, and `sign` subcommands. This ensures that your certificate chain will be included in the generated firmware image and that wolfBoot will verify the chain on boot, then verify the signature of the firmware image using the public key corresponding to the leaf certificate in the chain. Note that the user is responsible for properly constructing the certificate chain and ensuring that the leaf certificate is bound to the firmware signing key pair, as well as properly provisioning the HSM with the root CA certificate at the expected NVM object ID specified by the HAL.
|
||||
|
||||
### Dummy Certificate Chain
|
||||
|
||||
If you just want to test out the certificate verifcation functionality, `wbaurixtool.sh` can generate and use a dummy certificate chain by providing the `--dummy-certchain` option to the `keygen`, `sign`, `macros`, `lcf`, and `nvm` subcommands. This will cause the keygen step to generate a dummy root CA at `test-dummy-ca/root-ca.der`, well as a dummy certificate chain at `test-dummy-ca/raw-chain.der` using the specified algorithm. The generated chain consists of a single intermediate as well as a leaf (signing) certificate whose identity is bound to the generated firmware signing key pair. The subsequent commands will then ensure this generated chain is used by wolfBoot. Additionally, the `nvm` subcommand will create an NVM image containing the generated root CA that can be loaded into HSM NVM.
|
||||
|
||||
**Note: The `--dummy-certchain` option is intended for development and testing. For production use, generate and use your own certificate chain.**
|
||||
|
||||
## Building: Command Sequence
|
||||
|
||||
|
@ -309,7 +380,7 @@ cd $SCRIPTS_DIR
|
|||
# Generate keys, as well as configuration macros and linker script based on the selected signature algorithm
|
||||
./wbaurixtool.sh [--hsm] keygen --sign-algo ecc256 --hash-algo sha256 macros lcf
|
||||
|
||||
# If using wolfHSM, generate key NVM image
|
||||
# If using wolfHSM, generate key NVM image (make sure you have compiled whnvmtool before running this command)
|
||||
./wbaurixtool.sh nvm
|
||||
# Load NVM image hexfile to the device
|
||||
# ...
|
||||
|
|
|
@ -453,6 +453,9 @@
|
|||
<option id="com.infineon.aurix.buildsystem.managed.tool.c.link.option.ldflags.708051953" name="Linker flags" superClass="com.infineon.aurix.buildsystem.managed.tool.c.link.option.ldflags" useByScannerDiscovery="false" value="-mtc162 -Wl,--gc-sections -Wl,-Map,output.map" valueType="string"/>
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.infineon.aurix.buildsystem.managed.tool.c.link.option.userobjs.1601921229" name="Other objects" superClass="com.infineon.aurix.buildsystem.managed.tool.c.link.option.userobjs" useByScannerDiscovery="false" valueType="userObjs">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx-wolfHSM/TriCore Debug (GCC)/wolfBoot/hal/aurix_tc3xx.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx-wolfHSM/TriCore Debug (GCC)/Libraries/iLLD/TC37A/Tricore/Asclin/Asc/IfxAsclin_Asc.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx-wolfHSM/TriCore Debug (GCC)/Libraries/iLLD/TC37A/Tricore/Asclin/Std/IfxAsclin.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx-wolfHSM/TriCore Debug (GCC)/wolfBoot/src/string.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx-wolfHSM/TriCore Debug (GCC)/wolfBoot/src/libwolfboot.o}""/>
|
||||
</option>
|
||||
<inputType id="com.infineon.aurix.buildsystem.managed.c.linker.inputType.1147881076" superClass="com.infineon.aurix.buildsystem.managed.c.linker.inputType"/>
|
||||
|
@ -543,7 +546,7 @@
|
|||
<listOptionValue builtIn="false" value="PART_SWAP_EXT"/>
|
||||
<listOptionValue builtIn="false" value="RAM_CODE"/>
|
||||
</option>
|
||||
<option id="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.misc.other.1199404591" superClass="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.misc.other" value="-mtc162 -c -fmessage-length=0" valueType="string"/>
|
||||
<option id="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.misc.other.1199404591" name="Other flags" superClass="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-mtc162 -c -fmessage-length=0" valueType="string"/>
|
||||
<inputType id="com.infineon.aurix.buildsystem.managed.tool.c.compiler.inputType.1990995811" superClass="com.infineon.aurix.buildsystem.managed.tool.c.compiler.inputType"/>
|
||||
</tool>
|
||||
<tool id="com.infineon.aurix.buildsystem.managed.tool.cpp.compiler.669528986" name="AURIX G++ Compiler" superClass="com.infineon.aurix.buildsystem.managed.tool.cpp.compiler">
|
||||
|
|
|
@ -121,10 +121,10 @@ MEMORY
|
|||
pfls1_hdr (rx!p): org = LCF_WOLFBOOT_BOOT_PART_BASEADDR, len = LCF_WOLFBOOT_HEADER_OFFSET
|
||||
|
||||
/* pfls1 is the remainder of the wolfBoot BOOT partition. Everything goes here */
|
||||
pfls1 (rx!p): org = LCF_CODE_BASE_ADDR, len = (0x17E000 - LCF_WOLFBOOT_HEADER_OFFSET)
|
||||
pfls1 (rx!p): org = LCF_CODE_BASE_ADDR, len = (0x17C000 - LCF_WOLFBOOT_HEADER_OFFSET)
|
||||
|
||||
/* reserved for wolfBoot UPDATE partition */
|
||||
pfls1_update (rwx!p): org = 0xA047E000, len = 0x17E000 /* ~1.5MiB */
|
||||
pfls1_update (rwx!p): org = 0xA047C000, len = 0x17C000 /* ~1.5MiB */
|
||||
|
||||
/* SWAP sector for wolfBoot image update */
|
||||
pfls1_swap (rwx!p): org = 0xA05FC000, len = 16K /* last sector of PFLASH1 */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -440,6 +440,9 @@
|
|||
<listOptionValue builtIn="false" value="PART_SWAP_EXT"/>
|
||||
</option>
|
||||
<option id="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.misc.other.739113076" name="Other flags" superClass="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.misc.other" useByScannerDiscovery="false" value="-c -fmessage-length=0 -mtc162" valueType="string"/>
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.include.files.884786319" name="Include files (-include)" superClass="com.infineon.aurix.buildsystem.managed.tool.c.compiler.option.include.files" useByScannerDiscovery="false" valueType="includeFiles">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx/wolfBoot/include/image.h}""/>
|
||||
</option>
|
||||
<inputType id="com.infineon.aurix.buildsystem.managed.tool.c.compiler.inputType.1480422611" superClass="com.infineon.aurix.buildsystem.managed.tool.c.compiler.inputType"/>
|
||||
</tool>
|
||||
<tool id="com.infineon.aurix.buildsystem.managed.tool.cpp.compiler.366043271" name="AURIX G++ Compiler" superClass="com.infineon.aurix.buildsystem.managed.tool.cpp.compiler">
|
||||
|
@ -453,6 +456,9 @@
|
|||
<option id="com.infineon.aurix.buildsystem.managed.tool.c.link.option.ldflags.708051953" name="Linker flags" superClass="com.infineon.aurix.buildsystem.managed.tool.c.link.option.ldflags" useByScannerDiscovery="false" value="-mtc162 -Wl,--gc-sections -Wl,-Map,output.map" valueType="string"/>
|
||||
<option IS_BUILTIN_EMPTY="false" IS_VALUE_EMPTY="false" id="com.infineon.aurix.buildsystem.managed.tool.c.link.option.userobjs.1601921229" name="Other objects" superClass="com.infineon.aurix.buildsystem.managed.tool.c.link.option.userobjs" useByScannerDiscovery="false" valueType="userObjs">
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx/TriCore Debug (GCC)/wolfBoot/hal/aurix_tc3xx.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx/TriCore Debug (GCC)/Libraries/iLLD/TC37A/Tricore/Asclin/Std/IfxAsclin.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx/TriCore Debug (GCC)/Libraries/iLLD/TC37A/Tricore/Asclin/Asc/IfxAsclin_Asc.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx/TriCore Debug (GCC)/wolfBoot/src/string.o}""/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/wolfBoot-tc3xx/TriCore Debug (GCC)/wolfBoot/src/libwolfboot.o}""/>
|
||||
</option>
|
||||
<inputType id="com.infineon.aurix.buildsystem.managed.c.linker.inputType.1147881076" superClass="com.infineon.aurix.buildsystem.managed.c.linker.inputType"/>
|
||||
|
@ -469,6 +475,7 @@
|
|||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
|
||||
<storageModule moduleId="com.infineon.aurix.buildsystem.build.autodiscovery.settings"/>
|
||||
</cconfiguration>
|
||||
<cconfiguration id="com.infineon.aurix.buildsystem.managed.external.gcc.builtin.configuration.release.856945873">
|
||||
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.infineon.aurix.buildsystem.managed.external.gcc.builtin.configuration.release.856945873" moduleId="org.eclipse.cdt.core.settings" name="TriCore Release (GCC)">
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.configuration.binary.1914762785" name="TriCore Debug (TASKING)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="com.infineon.aurix.buildsystem.managed.TaskingBuiltintSpecsDetector" ref="shared-provider"/>
|
||||
</extension>
|
||||
</configuration>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.configuration.binary.697039770" name="TriCore Release (TASKING)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="com.infineon.aurix.buildsystem.managed.TaskingBuiltintSpecsDetector" ref="shared-provider"/>
|
||||
</extension>
|
||||
</configuration>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.external.gcc.builtin.configuration.debug.1333370870" name="TriCore Debug (GCC)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider class="com.infineon.aurix.buildsystem.managed.gcc.AURIXGCC11BuiltinSpecsDetector" console="false" env-hash="1122385352849106138" id="com.infineon.aurix.buildsystem.managed.CrossGCC11BuiltinSpecsDetector" keep-relative-paths="false" name="AURIXCrossGCC11compilerSpecsDetector" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
</extension>
|
||||
</configuration>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.external.gcc.builtin.configuration.release.856945873" name="TriCore Release (GCC)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider class="com.infineon.aurix.buildsystem.managed.gcc.AURIXGCC11BuiltinSpecsDetector" console="false" env-hash="1122385352849106138" id="com.infineon.aurix.buildsystem.managed.CrossGCC11BuiltinSpecsDetector" keep-relative-paths="false" name="AURIXCrossGCC11compilerSpecsDetector" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
</extension>
|
||||
</configuration>
|
||||
</project>
|
|
@ -121,10 +121,10 @@ MEMORY
|
|||
pfls1_hdr (rx!p): org = LCF_WOLFBOOT_BOOT_PART_BASEADDR, len = LCF_WOLFBOOT_HEADER_OFFSET
|
||||
|
||||
/* pfls1 is the remainder of the wolfBoot BOOT partition. Everything goes here */
|
||||
pfls1 (rx!p): org = LCF_CODE_BASE_ADDR, len = (0x17E000 - LCF_WOLFBOOT_HEADER_OFFSET)
|
||||
pfls1 (rx!p): org = LCF_CODE_BASE_ADDR, len = (0x17C000 - LCF_WOLFBOOT_HEADER_OFFSET)
|
||||
|
||||
/* reserved for wolfBoot UPDATE partition */
|
||||
pfls1_update (rwx!p): org = 0xA047E000, len = 0x17E000 /* ~1.5MiB */
|
||||
pfls1_update (rwx!p): org = 0xA047C000, len = 0x17C000 /* ~1.5MiB */
|
||||
|
||||
/* SWAP sector for wolfBoot image update */
|
||||
pfls1_swap (rwx!p): org = 0xA05FC000, len = 16K /* last sector of PFLASH1 */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -123,18 +123,11 @@ MEMORY
|
|||
/* wolfBoot program code - all of this project's executable code goes here */
|
||||
pfls0_nc (rx!p): org = 0xA00A8000, len = 0x23000 /* 140K total (incl 32K for startup) */
|
||||
|
||||
/* reserved for wolfBoot BOOT partition */
|
||||
pfls1_boot (rwx!p): org = 0x80300000, len = 0x17E000 /* ~1.5MiB */
|
||||
pfls1_boot_nc (rwx!p): org = 0xA0300000, len = 0x17E000 /* ~1.5MiB */
|
||||
/* reserved for BOOT, UPDATE, and SWAP partitions */
|
||||
pfls1(rwx!p): org = 0x80300000, len = 0x300000 /* 3MiB */
|
||||
pfls1_nc(rwx!p): org = 0xA0300000, len = 0x300000 /* 3MiB */
|
||||
|
||||
/* reserved for wolfBoot UPDATE partition */
|
||||
pfls1_update (rwx!p): org = 0x8047E000, len = 0x17E000 /* ~1.5MiB */
|
||||
pfls1_update_nc (rwx!p): org = 0xA047E000, len = 0x17E000 /* ~1.5MiB */
|
||||
|
||||
/* SWAP sector for wolfBoot image update */
|
||||
pfls1_swap (rwx!p): org = 0x805FC000, len = 16K /* last sector of PFLASH1 */
|
||||
|
||||
dfls0 (rx!p): org = 0xaf000000, len = 256K
|
||||
fls0 (rx!p): org = 0xaf000000, len = 256K
|
||||
|
||||
ucb (rx!p): org = 0xaf400000, len = 24K
|
||||
|
||||
|
|
|
@ -6,3 +6,6 @@
|
|||
@WOLFBOOT_USE_WOLFHSM_PUBKEY_ID@
|
||||
@ML_DSA_LEVEL@
|
||||
@ML_DSA_IMAGE_SIGNATURE_SIZE@
|
||||
@WOLFBOOT_ELF@
|
||||
@WOLFBOOT_ELF_FLASH_SCATTER@
|
||||
@WOLFBOOT_CERT_CHAIN_VERIFY@
|
|
@ -26,5 +26,6 @@
|
|||
#define WOLFHSM_CFG_H_
|
||||
|
||||
#define WOLFHSM_CFG_DMA
|
||||
#define WOLFHSM_CFG_CERTIFICATE_MANAGER
|
||||
|
||||
#endif /* WOLFHSM_CFG_H_ */
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,41 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.configuration.binary.1019631072" name="TriCore Debug (TASKING)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="com.infineon.aurix.buildsystem.managed.TaskingBuiltintSpecsDetector" ref="shared-provider"/>
|
||||
</extension>
|
||||
</configuration>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.configuration.binary.394981185" name="TriCore Release (TASKING)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="com.infineon.aurix.buildsystem.managed.TaskingBuiltintSpecsDetector" ref="shared-provider"/>
|
||||
</extension>
|
||||
</configuration>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.external.gcc.builtin.configuration.debug.401330509" name="TriCore Debug (GCC)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider class="com.infineon.aurix.buildsystem.managed.gcc.AURIXGCC11BuiltinSpecsDetector" console="false" env-hash="1122385352849106138" id="com.infineon.aurix.buildsystem.managed.CrossGCC11BuiltinSpecsDetector" keep-relative-paths="false" name="AURIXCrossGCC11compilerSpecsDetector" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
</extension>
|
||||
</configuration>
|
||||
<configuration id="com.infineon.aurix.buildsystem.managed.external.gcc.builtin.configuration.release.1853938077" name="TriCore Release (GCC)">
|
||||
<extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
|
||||
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
|
||||
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
|
||||
<provider class="com.infineon.aurix.buildsystem.managed.gcc.AURIXGCC11BuiltinSpecsDetector" console="false" env-hash="1122385352849106138" id="com.infineon.aurix.buildsystem.managed.CrossGCC11BuiltinSpecsDetector" keep-relative-paths="false" name="AURIXCrossGCC11compilerSpecsDetector" parameter="${COMMAND} ${FLAGS} -E -P -v -dD "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
</extension>
|
||||
</configuration>
|
||||
</project>
|
|
@ -123,16 +123,9 @@ MEMORY
|
|||
/* wolfBoot program code - all of this project's executable code goes here */
|
||||
pfls0_nc (rx!p): org = 0xA00A8000, len = 0x23000 /* 140K total (incl 32K for startup) */
|
||||
|
||||
/* reserved for wolfBoot BOOT partition */
|
||||
pfls1_boot (rwx!p): org = 0x80300000, len = 0x17E000 /* ~1.5MiB */
|
||||
pfls1_boot_nc (rwx!p): org = 0xA0300000, len = 0x17E000 /* ~1.5MiB */
|
||||
|
||||
/* reserved for wolfBoot UPDATE partition */
|
||||
pfls1_update (rwx!p): org = 0x8047E000, len = 0x17E000 /* ~1.5MiB */
|
||||
pfls1_update_nc (rwx!p): org = 0xA047E000, len = 0x17E000 /* ~1.5MiB */
|
||||
|
||||
/* SWAP sector for wolfBoot image update */
|
||||
pfls1_swap (rwx!p): org = 0x805FC000, len = 16K /* last sector of PFLASH1 */
|
||||
/* reserved for BOOT, UPDATE, and SWAP partitions */
|
||||
pfls1(rwx!p): org = 0x80300000, len = 0x300000 /* 3MiB */
|
||||
pfls1_nc(rwx!p): org = 0xA0300000, len = 0x300000 /* 3MiB */
|
||||
|
||||
dfls0 (rx!p): org = 0xaf000000, len = 256K
|
||||
|
||||
|
|
|
@ -6,3 +6,5 @@
|
|||
@WOLFBOOT_USE_WOLFHSM_PUBKEY_ID@
|
||||
@ML_DSA_LEVEL@
|
||||
@ML_DSA_IMAGE_SIGNATURE_SIZE@
|
||||
@WOLFBOOT_ELF@
|
||||
@WOLFBOOT_ELF_FLASH_SCATTER@
|
15
Makefile
15
Makefile
|
@ -229,6 +229,7 @@ $(PRIVATE_KEY):
|
|||
$(Q)(test $(SIGN) = NONE) || ($(SIGN_ENV) "$(KEYGEN_TOOL)" $(KEYGEN_OPTIONS) -g $(PRIVATE_KEY)) || true
|
||||
$(Q)(test $(SIGN) = NONE) && (echo "// SIGN=NONE" > src/keystore.c) || true
|
||||
$(Q)(test "$(FLASH_OTP_KEYSTORE)" = "1") && (make -C tools/keytools/otp) || true
|
||||
$(Q)(test $(SIGN) = NONE) || (test "$(CERT_CHAIN_VERIFY)" = "") || (test "$(CERT_CHAIN_GEN)" = "") || (tools/scripts/sim-gen-dummy-chain.sh --algo $(CERT_CHAIN_GEN_ALGO) --leaf $(PRIVATE_KEY))
|
||||
|
||||
$(SECONDARY_PRIVATE_KEY): $(PRIVATE_KEY) keystore.der
|
||||
$(Q)$(MAKE) keytools_check
|
||||
|
@ -243,6 +244,12 @@ keytools:
|
|||
@echo "Building key tools"
|
||||
@$(MAKE) -C tools/keytools -j
|
||||
|
||||
squashelf:
|
||||
@echo "Building squashelf tool"
|
||||
@$(MAKE) -C tools/squashelf -j
|
||||
|
||||
squashelf_check: squashelf
|
||||
|
||||
tpmtools: include/target.h keys
|
||||
@echo "Building TPM tools"
|
||||
@$(MAKE) -C tools/tpm -s clean
|
||||
|
@ -267,6 +274,10 @@ test-app/image.elf: wolfboot.elf
|
|||
$(Q)$(MAKE) -C test-app WOLFBOOT_ROOT="$(WOLFBOOT_ROOT)" image.elf
|
||||
$(Q)$(SIZE) test-app/image.elf
|
||||
|
||||
ifeq ($(ELF_FLASH_SCATTER),1)
|
||||
test-app/image.elf: squashelf
|
||||
endif
|
||||
|
||||
assemble_internal_flash.dd: FORCE
|
||||
$(Q)$(BINASSEMBLE) internal_flash.dd \
|
||||
0 wolfboot.bin \
|
||||
|
@ -376,9 +387,11 @@ utilsclean: clean
|
|||
$(Q)$(MAKE) -C tools/uart-flash-server -s clean
|
||||
$(Q)$(MAKE) -C tools/unit-tests -s clean
|
||||
$(Q)$(MAKE) -C tools/keytools/otp -s clean
|
||||
$(Q)$(MAKE) -C tools/squashelf -s clean
|
||||
|
||||
keysclean: clean
|
||||
$(Q)rm -f *.pem *.der tags ./src/*_pub_key.c ./src/keystore.c include/target.h
|
||||
$(Q)(test "$(CERT_CHAIN_GEN)" = "") || rm -rf test-dummy-ca || true
|
||||
|
||||
distclean: clean keysclean utilsclean
|
||||
$(Q)rm -f *.bin *.elf
|
||||
|
@ -467,4 +480,4 @@ pico-sdk-info: FORCE
|
|||
|
||||
FORCE:
|
||||
|
||||
.PHONY: FORCE clean keytool_check
|
||||
.PHONY: FORCE clean keytool_check squashelf_check
|
||||
|
|
17
arch.mk
17
arch.mk
|
@ -156,6 +156,18 @@ ifeq ($(ARCH),ARM)
|
|||
SPI_TARGET=stm32
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),pic32cz)
|
||||
ARCH_FLASH_OFFSET=0x08000000
|
||||
CORTEX_M7=1
|
||||
OBJS+=hal/pic32c.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),pic32ck)
|
||||
ARCH_FLASH_OFFSET=0x08000000
|
||||
CORTEX_M33=1
|
||||
OBJS+=hal/pic32c.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),stm32l4)
|
||||
SPI_TARGET=stm32
|
||||
ARCH_FLASH_OFFSET=0x08000000
|
||||
|
@ -458,7 +470,8 @@ ifeq ($(ARCH),RENESAS_RX)
|
|||
|
||||
OBJS+=./lib/wolfssl/wolfcrypt/src/cryptocb.o \
|
||||
./lib/wolfssl/wolfcrypt/src/port/Renesas/renesas_common.o \
|
||||
./lib/wolfssl/wolfcrypt/src/port/Renesas/renesas_tsip_util.o
|
||||
./lib/wolfssl/wolfcrypt/src/port/Renesas/renesas_tsip_util.o \
|
||||
./lib/wolfssl/wolfcrypt/src/port/Renesas/renesas_tsip_aes.o
|
||||
|
||||
# RX TSIP uses pre-compiled .a library by default
|
||||
ifneq ($(RX_TSIP_SRC),1)
|
||||
|
@ -1105,7 +1118,7 @@ ifeq ($(ARCH),sim)
|
|||
LD_END_GROUP=
|
||||
BOOT_IMG=test-app/image.elf
|
||||
CFLAGS+=-DARCH_SIM
|
||||
ifneq ($(ELF_SCATTERED),1)
|
||||
ifneq ($(ELF_FLASH_SCATTER),1)
|
||||
CFLAGS+=-DWOLFBOOT_USE_STDLIBC
|
||||
endif
|
||||
ifeq ($(FORCE_32BIT),1)
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
ARCH=ARM
|
||||
TARGET=pic32ck
|
||||
SIGN?=ED25519
|
||||
HASH?=SHA256
|
||||
VTOR?=1
|
||||
SPMATH?=1
|
||||
NO_MPU=1
|
||||
WOLFBOOT_PARTITION_SIZE=0x10000
|
||||
BOOTLOADER_PARTITION_SIZE=0x20000
|
||||
WOLFBOOT_SECTOR_SIZE=0x1000
|
||||
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x0c000000
|
||||
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0c07f000
|
||||
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0c0fe000
|
||||
TZEN=0
|
|
@ -0,0 +1,13 @@
|
|||
ARCH=ARM
|
||||
TARGET=pic32cz
|
||||
SIGN?=ED25519
|
||||
HASH?=SHA256
|
||||
VTOR?=1
|
||||
SPMATH?=1
|
||||
NO_MPU=1
|
||||
WOLFBOOT_PARTITION_SIZE=0x10000
|
||||
WOLFBOOT_SECTOR_SIZE=0x1000
|
||||
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x0c000000
|
||||
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0c200000
|
||||
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x0c030000
|
||||
#DUALBANK_SWAP=0
|
|
@ -5,7 +5,7 @@ HASH?=SHA256
|
|||
WOLFBOOT_SMALL_STACK?=0
|
||||
SPI_FLASH=0
|
||||
DEBUG=1
|
||||
ELF_SCATTERED=1
|
||||
ELF_FLASH_SCATTER=1
|
||||
ELF=1
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@ WOLFBOOT_SECTOR_SIZE=0x1000
|
|||
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000
|
||||
# if on external flash, it should be multiple of system page size
|
||||
|
||||
# Address from 0x100000 to 0x1FFFFF is reserved for ELF_SCATTERED
|
||||
# Address from 0x100000 to 0x1FFFFF is reserved for ELF_FLASH_SCATTER
|
||||
|
||||
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x200000
|
||||
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x280000
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
ARCH=sim
|
||||
TARGET=sim
|
||||
SIGN?=ECC256
|
||||
HASH?=SHA256
|
||||
WOLFBOOT_SMALL_STACK?=0
|
||||
SPI_FLASH=0
|
||||
DEBUG=1
|
||||
|
||||
# Cert chain options
|
||||
CERT_CHAIN_VERIFY=1
|
||||
CERT_CHAIN_GEN=1
|
||||
|
||||
# Ensure header is large enough to hold the cert chain (check sign tool output)
|
||||
# for actual length
|
||||
IMAGE_HEADER_SIZE=2048
|
||||
|
||||
# If SIGN=RSA4096, use the below options
|
||||
#WOLFBOOT_HUGE_STACK=1
|
||||
#IMAGE_HEADER_SIZE=4096
|
||||
|
||||
# wolfHSM options
|
||||
WOLFHSM_CLIENT=1
|
||||
|
||||
# sizes should be multiple of system page size
|
||||
#WOLFBOOT_PARTITION_SIZE=0x40000
|
||||
WOLFBOOT_PARTITION_SIZE=0x100000
|
||||
WOLFBOOT_SECTOR_SIZE=0x1000
|
||||
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80000
|
||||
# if on external flash, it should be multiple of system page size
|
||||
#WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x100000
|
||||
#WOLFBOOT_PARTITION_SWAP_ADDRESS=0x180000
|
||||
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x180000
|
||||
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x280000
|
||||
|
||||
# required for keytools
|
||||
WOLFBOOT_FIXED_PARTITIONS=1
|
||||
|
||||
# For debugging XMALLOC/XFREE
|
||||
#CFLAGS_EXTRA+=-DWOLFBOOT_DEBUG_MALLOC
|
|
@ -7,7 +7,7 @@ SPI_FLASH=0
|
|||
DEBUG=1
|
||||
FORCE_32BIT=1
|
||||
ELF=1
|
||||
ELF_SCATTERED=1
|
||||
ELF_FLASH_SCATTER=1
|
||||
|
||||
# sizes should be multiple of system page size
|
||||
WOLFBOOT_PARTITION_SIZE=0x40000
|
||||
|
|
|
@ -17,7 +17,7 @@ Platforms Supported:
|
|||
All of the Renesas examples support using e2Studio.
|
||||
The Renesas RX parts support using wolfBoot Makefile's with the rx-elf-gcc cross-compiler and example .config files.
|
||||
|
||||
### Security Key Management Tool (SKMT) Key Wrapping
|
||||
## Security Key Management Tool (SKMT) Key Wrapping
|
||||
|
||||
1) Setup a Renesas KeyWrap account and do the PGP key exchange.
|
||||
https://dlm.renesas.com/keywrap
|
||||
|
@ -34,12 +34,13 @@ Use GPG4Win and the Sign/Encrypt option. Sign with your own GPG key and encrypt
|
|||
It will use the Hidden Root Key (HRK) that both Renesas and the RX TSIP have pre-provisioned from Renesas Factory.
|
||||
Result is `sample.key_enc.key`. Example: `00000001 6CCB9A1C 8AA58883 B1CB02DE 6C37DA60 54FB94E2 06EAE720 4D9CCF4C 6EEB288C`
|
||||
|
||||
### RX TSIP
|
||||
## RX TSIP
|
||||
|
||||
1) Build key tools for Renesas
|
||||
|
||||
```sh
|
||||
# Build keytools for Renesas RX (TSIP)
|
||||
# Use RENESAS_KEY=2 for TSIP
|
||||
$ make keytools RENESAS_KEY=2
|
||||
```
|
||||
|
||||
|
@ -163,8 +164,36 @@ Output image(s) successfully created.
|
|||
|
||||
Download files to flash using Renesas flash programmer.
|
||||
|
||||
## RX TSIP AES Encryption (optional)
|
||||
|
||||
#### RX TSIP Benchmarks
|
||||
Create a wrapped AES key for encrypting/decrypting the update
|
||||
|
||||
Example key: `fwenc.key`: e07227e477450b1ca266078e217a3c89cbae827a7bb117ff851bc25300163575
|
||||
Note: `.config` must include `ENCRYPT=1` and `ENCRYPT_WITH_AES256=1`
|
||||
|
||||
```sh
|
||||
$ C:\Renesas\SecurityKeyManagementTool\cli\skmt.exe -genkey -ufpk file=./sample.key -wufpk file=./sample.key_enc.key -key file=./fwenc.key -mcu RX-TSIP -keytype AES-256 -output include/enckey_data.c -filetype csource -keyname wrap_enc_key -iv A8B14B0F5F09D73F31D4777FC0103FB4
|
||||
Output File: C:\CPG_Controls\wolfboot\include\enckey_data.h
|
||||
Output File: C:\CPG_Controls\wolfboot\include\enckey_data.c
|
||||
UFPK: B94A2B961C75510174F0C967ECFC20B377C7FB256DB627B1BFFADEE05EE98AC4
|
||||
W-UFPK: 000000016CCB9A1C8AA58883B1CB02DE6C37DA6054FB94E206EAE7204D9CCF4C6EEB288C
|
||||
IV: A8B14B0F5F09D73F31D4777FC0103FB4
|
||||
Encrypted key: 3C39BE75E9CA5CB9D2D0BBDE111CABC894A2B13F857399B05E7B140518F35D05CD97D8DF20817CEEBA2F207CC90BAF2C
|
||||
|
||||
$ C:\Renesas\SecurityKeyManagementTool\cli\skmt.exe -genkey -ufpk file=./sample.key -wufpk file=./sample.key_enc.key -key file=./fwenc.key -mcu RX-TSIP -keytype AES-256 -output fwenc.srec -filetype "mot" -address FFFF0100 -iv A8B14B0F5F09D73F31D4777FC0103FB4
|
||||
Output File: C:\CPG_Controls\wolfboot\fwenc.srec
|
||||
UFPK: B94A2B961C75510174F0C967ECFC20B377C7FB256DB627B1BFFADEE05EE98AC4
|
||||
W-UFPK: 000000016CCB9A1C8AA58883B1CB02DE6C37DA6054FB94E206EAE7204D9CCF4C6EEB288C
|
||||
IV: A8B14B0F5F09D73F31D4777FC0103FB4
|
||||
Encrypted key: 3C39BE75E9CA5CB9D2D0BBDE111CABC894A2B13F857399B05E7B140518F35D05CD97D8DF20817CEEBA2F207CC90BAF2C
|
||||
```
|
||||
|
||||
The offset for the wrapped AES key is determined by `RENESAS_TSIP_INSTALLEDENCKEY_ADDR` and defaults to `RENESAS_TSIP_INSTALLEDKEY_ADDR` + 0x100
|
||||
|
||||
The key needed for the firmware signing tool is the 32 byte AES Key + 16 byte IV.
|
||||
`echo "e07227e477450b1ca266078e217a3c89cbae827a7bb117ff851bc25300163575A8B14B0F5F09D73F31D4777FC0103FB4" | xxd -r -p - > fwkey.bin`
|
||||
|
||||
### RX TSIP Benchmarks
|
||||
|
||||
| Hardware | Clock | Algorithm | RX TSIP | Debug | Release (-Os) | Release (-O2) |
|
||||
| -------- | ------ | ----------------- | -------- | -------- | ------------- | ------------- |
|
||||
|
@ -172,3 +201,16 @@ Download files to flash using Renesas flash programmer.
|
|||
| RX72N | 240MHz | ECDSA Verify P256 | 2.73 ms | 469 ms | 135 ms | 107 ms |
|
||||
| RX65N | 120MHz | ECDSA Verify P384 | 18.57 ms | 4213 ms | 2179 ms | 1831 ms |
|
||||
| RX65N | 120MHz | ECDSA Verify P256 | 2.95 ms | 1208 ms | 602 ms | 517 ms |
|
||||
|
||||
|
||||
## RX Production Protection (recommendations)
|
||||
|
||||
1) Lockdown external serial programmer `SPCC.SPE = 0`
|
||||
2) Flash Access Window Setting Register (FAW)
|
||||
* BTFLG: Start-up Area Select FAW.BTFLG (1=FFFF E000h to FFFF FFFFh, 0=FFFF C000h to FFFF DFFFh)
|
||||
* FSPR - FAW.FSPR Access Window Protection (0=protections enabled) Once changed to 0 cannot be reset.
|
||||
3) ROM Code Protection Register `ROMCODE.CODE[31:0]`
|
||||
* 0000 0000h: ROM code protection enabled (ROM code protection 1)
|
||||
* 0000 0001h: ROM code protection enabled (ROM code protection 2)
|
||||
* Other than above: ROM code protection disabled
|
||||
4) Options Trusted Memory (TM) Enable `TMEF.TMEF[2:0] = b000` - prevents reading of blocks 8 and 9 (see 59.17 Trusted Memory) - Location for keys or code that should not be read
|
||||
|
|
|
@ -119,6 +119,14 @@ If none of the following is used, '--sha256' is assumed by default.
|
|||
|
||||
* `--sha3` Use sha3-384 for digest calculation on binary images and public keys.
|
||||
|
||||
#### Certificate Chain Options
|
||||
|
||||
wolfBoot also supports verifying firmware images using certificate chains instead of raw public keys. In this mode of operation, a certificate chain is included in the image manifest header, and the image is signed with the private key corresponding to the leaf certificate identity (signer cert). On boot, wolfBoot verifies the trust of the certificate chain (and therefore the signer cert) against a trusted root CA stored in the wolfHSM server, and if the chain is trusted, verifies the authenticity of the firmware image using the public key from the image signer certificate.
|
||||
|
||||
To generate an image for use with this mode, pass the `--cert-chain CERT_CHAIN.der` option to the sign tool, where `CERT_CHAIN.der` is a der encoded certificate chain containing one or more certificates in SSL order (leaf/signer cert last). Note that the sign tool still expects a signing private key to be provided as described above, and assumes that the public key of the signer cert in the chain corresponds to the signing private key.
|
||||
|
||||
Certificate chain verification of images is currently limited to use in conjunction with wolfHSM. See [wolfHSM.md](wolfHSM.md) for more details.
|
||||
|
||||
#### Target partition id (Multiple partition images, "self-update" feature)
|
||||
|
||||
If none of the following is used, "--id=1" is assumed by default. On systems
|
||||
|
@ -257,7 +265,7 @@ For a real-life example, see the section below.
|
|||
./tools/keytools/sign --rsa2048 --sha256 test-app/image.bin wolfboot_signing_private_key.der 1
|
||||
```
|
||||
|
||||
Note: The last argument is the “version” number.
|
||||
Note: The last argument is the "version" number.
|
||||
|
||||
### Signing Firmware with External Private Key (HSM)
|
||||
|
||||
|
|
154
docs/Targets.md
154
docs/Targets.md
|
@ -10,6 +10,8 @@ This README describes configuration of supported targets.
|
|||
* [Infineon AURIX TC3xx](#infineon-aurix-tc3xx)
|
||||
* [Intel x86-64 Intel FSP](#intel-x86_64-with-intel-fsp-support)
|
||||
* [Kontron VX3060-S2](#kontron-vx3060-s2)
|
||||
* [Microchip PIC32CK](#microchip-pic32ck)
|
||||
* [Microchip PIC32CZ](#microchip-pic32cz)
|
||||
* [Microchip SAMA5D3](#microchip-sama5d3)
|
||||
* [Microchip SAME51](#microchip-same51)
|
||||
* [Nordic nRF52840](#nordic-nrf52840)
|
||||
|
@ -45,7 +47,6 @@ This README describes configuration of supported targets.
|
|||
* [TI Hercules TMS570LC435](#ti-hercules-tms570lc435)
|
||||
* [Xilinx Zynq UltraScale](#xilinx-zynq-ultrascale)
|
||||
|
||||
|
||||
## STM32F4
|
||||
|
||||
Example 512KB partitioning on STM32-F407
|
||||
|
@ -1555,6 +1556,153 @@ at addresses 0x400000 and 0x800000, authenticate, load to DRAM and stage from
|
|||
Ensure that the application is compiled to run from `LOAD_ADDRESS`.
|
||||
Check `test-app/ARM-sama5d3.ld` for details.
|
||||
|
||||
## Microchip PIC32CK
|
||||
|
||||
The PIC32CK is a high-performance 32-bit microcontroller family from Microchip featuring an ARM Cortex-M33 core. wolfBoot has been tested on the PIC32CKSG Curiosity board, which has GPIO pins PD20 and PB25 connected to LED0 and LED1, respectively, for status indication.
|
||||
|
||||
### Configuration
|
||||
|
||||
The PIC32CK SG family models support TrustZone. The flash and memory areas marked as secure or non secure depend on configuration settings. If setting `TZEN=0`, wolfBoot ignores TrustZone configuration, with the net effect to stage the application in the secure domain. In this case the flash area used to store BOOT and UPDATE partition should be marked as secure. The config file provided in `config/examples/pic32ck.config` sets `TZEN=0` and uses flash partition addresses that are marked as secure under default settings.
|
||||
The PIC32CK supports a dual-bank update mechanism but, based on configuration settings, the swap may cause an area marked as secure to be mapped in non-secure flash space. For this reason `DUALBANK_SWAP` feature should be only used after precise configuration.
|
||||
|
||||
### Building
|
||||
|
||||
To build wolfBoot for the PIC32CK:
|
||||
|
||||
1. Configure the build using the example configuration file:
|
||||
|
||||
```sh
|
||||
cp config/examples/pic32ck.config .config
|
||||
make clean
|
||||
make
|
||||
```
|
||||
|
||||
2. Sign the application:
|
||||
|
||||
```sh
|
||||
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 1
|
||||
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 2
|
||||
```
|
||||
|
||||
### Programming and Testing
|
||||
|
||||
To program the flash chip using the JLink tool:
|
||||
|
||||
Identify the correct JLink device for your PIC32CK. In the examples the model is PIC32CK2051SG.
|
||||
|
||||
1. Run the following command:
|
||||
|
||||
```sh
|
||||
JLinkExe -device PIC32CK2051SG -if SWD -speed 4000 -autoconnect 1
|
||||
```
|
||||
|
||||
2. At the JLink prompt, use the following commands:
|
||||
|
||||
```
|
||||
halt
|
||||
reset
|
||||
erase
|
||||
loadfile wolfboot.bin 0x08000000
|
||||
loadfile test-app/image_v1_signed.bin 0x0c000000
|
||||
loadfile test-app/image_v2_signed.bin 0x0c07f000
|
||||
reset
|
||||
q
|
||||
```
|
||||
|
||||
3. Disconnect USB debugger and power cycle board. LED0 will turn on indicating version 1. Then press the reset button and LED1 will turn on indicating version 2.
|
||||
|
||||
### Programming with MPlab IPE
|
||||
|
||||
In order to program using the MPlab IPE, you need to create the hex files for wolfBoot, and the signed application images:
|
||||
|
||||
```bash
|
||||
arm-none-eabi-objcopy -O ihex wolfboot.elf wolfboot.hex
|
||||
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C000000 test-app/image_v1_signed.bin image_v1_signed.hex
|
||||
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C07F000 test-app/image_v2_signed.bin image_v2_signed.hex
|
||||
```
|
||||
|
||||
then enable advanced setting in the MPLAB IPE GUI, and enable the "Allow Import Multiple Hex file" option in the Production view.
|
||||
Once the option is enabled, load the hex files into the MPLAB IPE GUI (File -> Import -> Multiple hex) and program the device.
|
||||
|
||||
### Behavior During Testing
|
||||
|
||||
- The application version 1 will boot first. The application will trigger the update and light LED0. On the next reset, wolfBoot will update the application, boot application version 2, and turn on LED1.
|
||||
|
||||
|
||||
## Microchip PIC32CZ
|
||||
|
||||
The PIC32CZ is a high-performance 32-bit microcontroller family from Microchip featuring an ARM Cortex-M7 core. wolfBoot has been tested on the PIC32CZCA91 Curiosity board, which has GPIO pins PB21 and PB22 connected to LED0 and LED1, respectively, for status indication.
|
||||
|
||||
### Configuration
|
||||
|
||||
The PIC32CZ supports a dual-bank update mechanism that can be activated using the `DUALBANK_SWAP=1` option in the configuration file. When activated, the boot partition must be configured to reside in the lower Program Flash Memory (PFM) area, while the update partition should be in the upper PFM area. An example configuration for the PIC32CZ with 4MB RAM is provided in `config/examples/pic32cz.config`.
|
||||
|
||||
### Building
|
||||
|
||||
To build wolfBoot for the PIC32CZ:
|
||||
|
||||
1. Configure the build using the example configuration file:
|
||||
|
||||
```sh
|
||||
cp config/examples/pic32cz.config .config
|
||||
make clean
|
||||
make
|
||||
```
|
||||
|
||||
2. Sign the application:
|
||||
|
||||
```sh
|
||||
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 1
|
||||
./tools/keytools/sign --ed25519 --sha256 ./test-app/image.bin wolfboot_signing_private_key.der 2
|
||||
```
|
||||
|
||||
### Programming and Testing
|
||||
|
||||
To program the flash chip using the JLink tool:
|
||||
|
||||
Identify the correct JLink device for your PIC32CZ board. In the examples the model is PIC32CZ4010CA90.
|
||||
|
||||
1. Run the following command:
|
||||
|
||||
```sh
|
||||
JLinkExe -device PIC32CZ4010CA90 -if SWD -speed 4000 -autoconnect 1
|
||||
```
|
||||
|
||||
2. At the JLink prompt, use the following commands:
|
||||
|
||||
```
|
||||
halt
|
||||
reset
|
||||
erase
|
||||
loadfile wolfboot.bin 0x08000000
|
||||
loadfile test-app/image_v1_signed.bin 0x0c000000
|
||||
loadfile test-app/image_v2_signed.bin 0x0c200000
|
||||
reset
|
||||
q
|
||||
```
|
||||
|
||||
3. Disconnect USB debugger and power cycle board. LED0 will turn on indicating version 1. Then press the reset button and LED1 will turn on indicating version 2.
|
||||
|
||||
### Programming with MPLAB IPE
|
||||
|
||||
In order to program using the MPLAB IPE, you need to create the hex files for wolfBoot, and the signed application images:
|
||||
|
||||
```bash
|
||||
arm-none-eabi-objcopy -O ihex wolfboot.elf wolfboot.hex
|
||||
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C000000 test-app/image_v1_signed.bin image_v1_signed.hex
|
||||
arm-none-eabi-objcopy -I binary -O ihex --change-addresses=0x0C200000 test-app/image_v2_signed.bin image_v2_signed.hex
|
||||
```
|
||||
|
||||
then enable advanced setting in the MPLAB IPE GUI, and enable the "Allow Import Multiple Hex file" option in the Production view.
|
||||
Once the option is enabled, load the hex files into the MPLAB IPE GUI (File -> Import -> Multiple hex) and program the device.
|
||||
|
||||
### Behavior During Testing
|
||||
|
||||
The test behavior depends on whether the `DUALBANK_SWAP` feature is enabled:
|
||||
|
||||
- **If `DUALBANK_SWAP=1`:** The higher version of the application will be automatically selected, and LED1 will turn on.
|
||||
- **If `DUALBANK_SWAP=0`:** The application version 1 will boot first. The application will trigger the update and light LED0. On the next reset, wolfBoot will update the application, boot application version 2, and turn on LED1.
|
||||
|
||||
|
||||
## Microchip SAME51
|
||||
|
||||
|
@ -2453,7 +2601,7 @@ Boot header magic 0x00000000 invalid at 0x20000128
|
|||
Copy sector 1 (part 1->2)
|
||||
Copy sector 1 (part 0->1)
|
||||
Copy sector 1 (part 2->0)
|
||||
Erasing remainder of partitions (235 sectors)...
|
||||
Erasing remainder of partition (235 sectors)...
|
||||
Boot partition: 0xC000 (sz 4832, ver 0x2, type 0x201)
|
||||
Boot header magic 0x00000000 invalid at 0x20000128
|
||||
Copy sector 236 (part 0->2)
|
||||
|
@ -2495,7 +2643,7 @@ Copy sector 1 (part 2->0)
|
|||
Copy sector 2 (part 1->2)
|
||||
Copy sector 2 (part 0->1)
|
||||
Copy sector 2 (part 2->0)
|
||||
Erasing remainder of partitions (88 sectors)...
|
||||
Erasing remainder of partition (88 sectors)...
|
||||
Boot partition: 0x100C000 (sz 4120, ver 0x2, type 0x202)
|
||||
Update partition: 0x100000 (sz 4120, ver 0x1, type 0x201)
|
||||
Copy sector 90 (part 0->2)
|
||||
|
|
|
@ -171,4 +171,76 @@ of the patch. If all checks succeed, the new version is installed by applying th
|
|||
If the update is not confirmed, at the next reboot wolfBoot will restore the original base `image_v1_signed.bin`, using
|
||||
the reverse patch contained in the delta update bundle.
|
||||
|
||||
## ELF loading
|
||||
|
||||
wolfBoot supports loading ELF (Executable and Linkable Format) images via both the RAM [update_ram.c](../src/update_ram.c) and [flash update](../src/update_flash.c) mechanisms.
|
||||
|
||||
### RAM ELF loading
|
||||
|
||||
The wolfBoot RAM loader supports loading ELF images from flash into RAM before booting. When using the RAM loader [update_ram.c](../src/update_ram.c) with `WOLFBOOT_ELF` defined, wolfBoot will verify the ELF file signature and hash as stored in the boot or update partition, and then load the ELF file into RAM based on the LMA (Load Memory Address) of each section before jumping to the entry point.
|
||||
|
||||
### Flash ELF loading
|
||||
|
||||
The wolfBoot flash loader also supports loading ELF files containing scattered LMA (Load Memory Address) segments to their respective locations in flash. This feature allows firmware images to be distributed as ELF files with sections only containing loadable regions, rather than requiring a contiguous/flat binary image for the entire memory space or image size. The flash elf loading procedure only supports loading ELF file program segments into flash memory with the same access restrictions as the BOOT partition (e.g. will use the same hal_flash/ext_flash functions) and does not support loading sections into RAM.
|
||||
|
||||
#### How it works
|
||||
|
||||
When wolfBoot is compiled with `WOLFBOOT_ELF_FLASH_SCATTER` defined, it includes support for:
|
||||
|
||||
1. **Section Loading**: During boot or update, wolfBoot:
|
||||
- Parses the ELF headers to identify section locations
|
||||
- Loads each section into its designated memory address
|
||||
- Sets up the proper entry point for execution
|
||||
- Verifies the scattered hash after loading
|
||||
|
||||
2. **Dual-Layer Verification**: wolfBoot performs two distinct integrity checks:
|
||||
- Initial verification of the ELF file signature and integrity check (hash) as stored in the boot or update partition
|
||||
- A second "scattered hash" verification that re-computes the same image hash as in the manifest header, but computed over the actual loaded segments in their final memory locations (Load Memory Address - LMA) rather than their data in the ELF file
|
||||
|
||||
3. **Update Support**: The scattered ELF support is transparently integrated with wolfBoot's flash update mechanism:
|
||||
- ELF images can be used as update packages
|
||||
- The bootloader automatically handles loading and verifying scattered sections during the update process
|
||||
- If the scattered hash verification fails after an update, the system can fall back to the previous version
|
||||
|
||||
#### Using Scattered ELF Images
|
||||
|
||||
To use scattered ELF images:
|
||||
|
||||
1. Ensure wolfBoot is compiled with `WOLFBOOT_ELF` and `WOLFBOOT_ELF_FLASH_SCATTER`
|
||||
2. Build your firmware as an ELF file with the desired memory layout
|
||||
3. Preprocess the ELF file using [squashelf](../tools/squashelf/README.md) to strip the ELF file to just loadable sections and ensure it is compatible with wolfBoot (if building using wolfBoot's Makefile build system, this step is performed automatically)
|
||||
4. Sign the ELF image using the wolfBoot signing tools
|
||||
5. Transfer the signed ELF image to the target like any other update
|
||||
|
||||
The on boot or during update, the bootloader will automatically perform both layers of verification:
|
||||
|
||||
1. Verifying the signature and hash over the image in the BOOT or UPDATE partition
|
||||
2. Computing and verifying the scattered hash after loading sections to their final locations
|
||||
|
||||
Note: When using scattered ELF images, ensure that:
|
||||
|
||||
- The ELF file adheres to the ELF file specification and was generated by a toolchain supporting the target architecture
|
||||
- All section addresses are within valid executable memory regions and **do not overlap with the wolfBoot image, nor the BOOT, UPDATE and SWAP partitions**.
|
||||
|
||||
## Certificate Verification
|
||||
|
||||
wolfBoot supports authenticating images using certificate chains instead of raw public keys. in this mode of operation, a certificate chain is included in the image manifest header, and the image is signed with the private key corresponding to the leaf certificate identity (signer cert). On boot, wolfBoot verifies the trust of the certificate chain (and therefore the signer cert) against a trusted root CA stored in the wolfHSM server, and if the chain is trusted, verifies the authenticity of the firmware image using the public key from the image signer certificate.
|
||||
|
||||
To use this feature:
|
||||
|
||||
1. Enable the feature in your wolfBoot configuration by defining `WOLFBOOT_CERT_CHAIN_VERIFY`
|
||||
2. When signing firmware, include the certificate chain using the `--cert-chain` option:
|
||||
|
||||
```sh
|
||||
./tools/keytools/sign --rsa2048 --sha256 --cert-chain cert_chain.der test-app/image.bin private_key.der 1
|
||||
```
|
||||
|
||||
When verifying firmware, wolfBoot will:
|
||||
|
||||
1. Extract the certificate chain from the firmware header
|
||||
2. Verify the chain using the pre-provisioned root certificate
|
||||
3. Use the public key from the leaf certificate to verify the firmware signature
|
||||
|
||||
This feature is particularly useful in scenarios where you want to rotate signing keys without updating the bootloader, as you can simply resign the image with a new key, create a new certificate chain, then update the certificate chain in the firmware header.
|
||||
|
||||
Note: Currently, support for certificate verification is limited to use in conjuction with wolfHSM. Fore more information see [wolfHSM.md](wolfHSM.md).
|
||||
|
|
|
@ -31,6 +31,34 @@ wolfBoot supports using wolfHSM for the following algorithms:
|
|||
|
||||
Encrypted images with wolfHSM is not yet supported in wolfBoot. Note that every HAL target may not support all of these algorithms. Consult the platform-specific wolfBoot documentation for details.
|
||||
|
||||
## Additional Features
|
||||
|
||||
wolfBoot with wolfHSM also supports the following features:
|
||||
|
||||
### Certificate Verification
|
||||
|
||||
wolfBoot with wolfHSM supports certificate chain verification for firmware images. In this mode, instead of using raw public keys for signature verification, wolfBoot verifies firmware images using wolfHSM with a public key embedded in a certificate chain that is included in the image manifest header.
|
||||
|
||||
The certificate verification process with wolfHSM works as follows:
|
||||
|
||||
1. A root CA is created serving as the root of trust for the entire PKI system
|
||||
2. A signing keypair and corresponding identity certificate is created for signing firmware images
|
||||
3. The firmware image is signed with the signing private key
|
||||
4. A certificate chain is created consisting of the signing identity certificate and an optional number of intermediate certificates, where trust is chained back to the root CA.
|
||||
5. During the signing process, the image is signed with the signer private key and the certificate chain is embedded in the firmware image header.
|
||||
6. During boot, wolfBoot extracts the certificate chain from the firmware header
|
||||
7. wolfBoot uses the wolfHSM server to verify the certificate chain against a pre-provisioned root CA certificate stored on the HSM and caches the public key of the leaf certificate if the chain verifies as trusted
|
||||
8. If the chain is trusted, wolfBoot uses the cached public key from the leaf certificate to verify the firmware signature on the wolfHSM server
|
||||
|
||||
To use certificate verification with wolfHSM:
|
||||
|
||||
1. Enable `WOLFBOOT_CERT_CHAIN_VERIFY` in your wolfBoot configuration
|
||||
2. Ensure the wolfHSM server is configured with certificate manager support (`WOLFHSM_CFG_CERTIFICATE_MANAGER`)
|
||||
3. Pre-provision the root CA certificate on the wolfHSM server at the NVM ID specified by the HAL `hsmClientNvmIdCertRootCA`
|
||||
4. Sign firmware images with the `--cert-chain` option, providing a DER-encoded certificate chain
|
||||
|
||||
To build the simulator using wolfHSM for certificate verification, use [config/examples/sim-wolfHSM-certchain.config](config/examples/sim-wolfHSM-certchain.config).
|
||||
|
||||
## Configuration Options
|
||||
|
||||
This section describes the configuration options available for wolfHSM client integration. Note that these options should be configured automatically by the build system for each supported platform when wolfHSM support is enabled. Consult the platform-specific documentation for details on enabling wolfHSM support.
|
||||
|
|
|
@ -33,6 +33,11 @@
|
|||
#include "IfxPort.h" /* for IfxPort_* */
|
||||
#include "IfxScuRcu.h" /* for IfxScuRcu_performReset */
|
||||
#include "Ifx_Ssw_Infra.h" /* for Ifx_Ssw_jumpToFunction */
|
||||
#if defined(DEBUG_UART)
|
||||
#include "IfxAsclin_Asc.h"
|
||||
#include "Cpu/Irq/IfxCpu_Irq.h"
|
||||
#include "IfxCpu.h"
|
||||
#endif /* DEBUG_UART */
|
||||
|
||||
#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT
|
||||
/* wolfHSM headers */
|
||||
|
@ -81,6 +86,15 @@ static uint32_t sectorBuffer[WOLFBOOT_SECTOR_SIZE / sizeof(uint32_t)];
|
|||
#define LED_OFF(led)
|
||||
#endif /* WOLFBOOT_AURIX_GPIO_TIMING */
|
||||
|
||||
#if defined(DEBUG_UART)
|
||||
#define UART_PIN_RX IfxAsclin0_RXA_P14_1_IN /* RX pin of the board */
|
||||
#define UART_PIN_TX IfxAsclin0_TX_P14_0_OUT /* TX pin of the board */
|
||||
#define UART_BAUDRATE 115200
|
||||
static Ifx_ASCLIN* g_asclinRegs = &MODULE_ASCLIN0;
|
||||
static int uartInit(void);
|
||||
static int uartTx(const uint8_t c);
|
||||
#endif /* DEBUG_UART */
|
||||
|
||||
#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT
|
||||
int hal_hsm_init_connect(void);
|
||||
int hal_hsm_disconnect(void);
|
||||
|
@ -353,6 +367,10 @@ void hal_init(void)
|
|||
LED_OFF(LED_PROG);
|
||||
LED_OFF(LED_ERASE);
|
||||
LED_OFF(LED_READ);
|
||||
|
||||
#if defined(DEBUG_UART)
|
||||
uartInit();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -441,25 +459,91 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
|
|||
{
|
||||
LED_ON(LED_ERASE);
|
||||
|
||||
const uint32_t sectorAddr = GET_SECTOR_ADDR(address);
|
||||
const size_t numSectors =
|
||||
(len == 0) ? 0 : ((len - 1) / WOLFBOOT_SECTOR_SIZE) + 1;
|
||||
const IfxFlash_FlashType type = getFlashTypeFromAddr(address);
|
||||
/* Handle zero length case */
|
||||
if (len <= 0) {
|
||||
LED_OFF(LED_ERASE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Disable ENDINIT protection */
|
||||
const uint16 endInitSafetyPassword =
|
||||
const uint32_t startSectorAddr = GET_SECTOR_ADDR(address);
|
||||
const uint32_t endAddress = address + len - 1;
|
||||
const uint32_t endSectorAddr = GET_SECTOR_ADDR(endAddress);
|
||||
const IfxFlash_FlashType type = getFlashTypeFromAddr(address);
|
||||
const uint16 endInitSafetyPassword =
|
||||
IfxScuWdt_getSafetyWatchdogPasswordInline();
|
||||
IfxScuWdt_clearSafetyEndinitInline(endInitSafetyPassword);
|
||||
uint32_t currentSectorAddr;
|
||||
|
||||
IfxFlash_eraseMultipleSectors(sectorAddr, numSectors);
|
||||
/* If address and len are both sector-aligned, perform simple bulk erase */
|
||||
if ((address == startSectorAddr) &&
|
||||
(endAddress == endSectorAddr + WOLFBOOT_SECTOR_SIZE - 1)) {
|
||||
const size_t numSectors =
|
||||
(endSectorAddr - startSectorAddr) / WOLFBOOT_SECTOR_SIZE + 1;
|
||||
|
||||
/* Reenable ENDINIT protection */
|
||||
IfxScuWdt_setSafetyEndinitInline(endInitSafetyPassword);
|
||||
/* Disable ENDINIT protection */
|
||||
IfxScuWdt_clearSafetyEndinitInline(endInitSafetyPassword);
|
||||
|
||||
IfxFlash_waitUnbusy(FLASH_MODULE, type);
|
||||
IfxFlash_eraseMultipleSectors(startSectorAddr, numSectors);
|
||||
|
||||
/* Reenable ENDINIT protection */
|
||||
IfxScuWdt_setSafetyEndinitInline(endInitSafetyPassword);
|
||||
|
||||
IfxFlash_waitUnbusy(FLASH_MODULE, type);
|
||||
}
|
||||
/* For non-sector aligned erases, handle each sector carefully */
|
||||
else {
|
||||
/* Process each affected sector */
|
||||
for (currentSectorAddr = startSectorAddr;
|
||||
currentSectorAddr <= endSectorAddr;
|
||||
currentSectorAddr += WOLFBOOT_SECTOR_SIZE) {
|
||||
|
||||
/* Check if this is a partial sector erase */
|
||||
const int isFirstSector = (currentSectorAddr == startSectorAddr);
|
||||
const int isLastSector = (currentSectorAddr == endSectorAddr);
|
||||
const int isPartialStart =
|
||||
isFirstSector && (address > startSectorAddr);
|
||||
const int isPartialEnd =
|
||||
isLastSector &&
|
||||
(endAddress < (endSectorAddr + WOLFBOOT_SECTOR_SIZE - 1));
|
||||
|
||||
/* For partial sectors, need to read-modify-write */
|
||||
if (isPartialStart || isPartialEnd) {
|
||||
/* Read the sector into the sector buffer */
|
||||
cacheSector(currentSectorAddr, type);
|
||||
|
||||
/* Calculate which bytes within the sector to erase */
|
||||
uint32_t eraseStartOffset =
|
||||
isPartialStart ? (address - currentSectorAddr) : 0;
|
||||
|
||||
uint32_t eraseEndOffset = isPartialEnd
|
||||
? (endAddress - currentSectorAddr)
|
||||
: (WOLFBOOT_SECTOR_SIZE - 1);
|
||||
|
||||
uint32_t eraseLen = eraseEndOffset - eraseStartOffset + 1;
|
||||
|
||||
/* Fill the section to be erased with the erased byte value */
|
||||
memset((uint8_t*)sectorBuffer + eraseStartOffset,
|
||||
FLASH_BYTE_ERASED, eraseLen);
|
||||
|
||||
/* Erase the sector */
|
||||
IfxScuWdt_clearSafetyEndinitInline(endInitSafetyPassword);
|
||||
IfxFlash_eraseSector(currentSectorAddr);
|
||||
IfxScuWdt_setSafetyEndinitInline(endInitSafetyPassword);
|
||||
IfxFlash_waitUnbusy(FLASH_MODULE, type);
|
||||
|
||||
/* Program the modified buffer back */
|
||||
programCachedSector(currentSectorAddr, type);
|
||||
}
|
||||
/* For full sector erase, just erase directly */
|
||||
else {
|
||||
IfxScuWdt_clearSafetyEndinitInline(endInitSafetyPassword);
|
||||
IfxFlash_eraseSector(currentSectorAddr);
|
||||
IfxScuWdt_setSafetyEndinitInline(endInitSafetyPassword);
|
||||
IfxFlash_waitUnbusy(FLASH_MODULE, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LED_OFF(LED_ERASE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -581,6 +665,9 @@ const int hsmClientKeyIdPubKey = 0xFF;
|
|||
const int hsmClientDevIdCrypt = WH_DEV_ID;
|
||||
const int hsmClientKeyIdCrypt = 0xFF;
|
||||
#endif
|
||||
#ifdef WOLFBOOT_CERT_CHAIN_VERIFY
|
||||
const whNvmId hsmClientNvmIdCertRootCA = 1;
|
||||
#endif
|
||||
|
||||
|
||||
static int _cancelCb(uint16_t cancelSeq)
|
||||
|
@ -681,3 +768,118 @@ int hal_hsm_disconnect(void)
|
|||
|
||||
|
||||
#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT */
|
||||
|
||||
#if defined(DEBUG_UART)
|
||||
|
||||
static int uartInit(void)
|
||||
{
|
||||
/* Define local pin structures for init function */
|
||||
IfxAsclin_Rx_In uartRxPin = UART_PIN_RX;
|
||||
IfxAsclin_Tx_Out uartTxPin = UART_PIN_TX;
|
||||
|
||||
IfxAsclin_enableModule(g_asclinRegs);
|
||||
IfxAsclin_setClockSource(g_asclinRegs, IfxAsclin_ClockSource_noClock);
|
||||
|
||||
IfxAsclin_initRxPin(&uartRxPin, IfxPort_InputMode_pullUp,
|
||||
IfxPort_PadDriver_cmosAutomotiveSpeed1);
|
||||
IfxAsclin_initTxPin(&uartTxPin, IfxPort_OutputMode_pushPull,
|
||||
IfxPort_PadDriver_cmosAutomotiveSpeed1);
|
||||
IfxAsclin_setFrameMode(g_asclinRegs, IfxAsclin_FrameMode_initialise);
|
||||
|
||||
/* Configure baudrate - must temporarily enable clocks */
|
||||
IfxAsclin_setClockSource(g_asclinRegs, IfxAsclin_ClockSource_ascFastClock);
|
||||
IfxAsclin_setPrescaler(g_asclinRegs, 1);
|
||||
if (IfxAsclin_setBitTiming(
|
||||
g_asclinRegs, (float32)UART_BAUDRATE,
|
||||
IfxAsclin_OversamplingFactor_16,
|
||||
IfxAsclin_SamplePointPosition_9, /* Sample point 9 */
|
||||
IfxAsclin_SamplesPerBit_three) == FALSE) { /* Three samples */
|
||||
IfxAsclin_disableModule(g_asclinRegs);
|
||||
return -1;
|
||||
}
|
||||
IfxAsclin_setClockSource(g_asclinRegs, IfxAsclin_ClockSource_noClock);
|
||||
|
||||
IfxAsclin_setDataLength(g_asclinRegs, IfxAsclin_DataLength_8);
|
||||
IfxAsclin_enableParity(g_asclinRegs, FALSE);
|
||||
IfxAsclin_setStopBit(g_asclinRegs, IfxAsclin_StopBit_1);
|
||||
IfxAsclin_setIdleDelay(g_asclinRegs, IfxAsclin_IdleDelay_0);
|
||||
|
||||
IfxAsclin_enableLoopBackMode(g_asclinRegs, FALSE);
|
||||
IfxAsclin_setShiftDirection(g_asclinRegs,
|
||||
IfxAsclin_ShiftDirection_lsbFirst);
|
||||
|
||||
IfxAsclin_setRxFifoOutletWidth(g_asclinRegs, IfxAsclin_RxFifoOutletWidth_1);
|
||||
IfxAsclin_setRxFifoInterruptLevel(g_asclinRegs,
|
||||
IfxAsclin_RxFifoInterruptLevel_1);
|
||||
IfxAsclin_setRxFifoInterruptMode(g_asclinRegs,
|
||||
IfxAsclin_FifoInterruptMode_combined);
|
||||
IfxAsclin_setTxFifoInletWidth(g_asclinRegs, IfxAsclin_TxFifoInletWidth_1);
|
||||
IfxAsclin_setTxFifoInterruptLevel(g_asclinRegs,
|
||||
IfxAsclin_TxFifoInterruptLevel_15);
|
||||
IfxAsclin_setTxFifoInterruptMode(g_asclinRegs,
|
||||
IfxAsclin_FifoInterruptMode_combined);
|
||||
|
||||
IfxAsclin_setFrameMode(g_asclinRegs, IfxAsclin_FrameMode_asc);
|
||||
|
||||
IfxAsclin_setClockSource(g_asclinRegs, IfxAsclin_ClockSource_ascFastClock);
|
||||
|
||||
IfxAsclin_disableAllFlags(g_asclinRegs);
|
||||
IfxAsclin_clearAllFlags(g_asclinRegs);
|
||||
|
||||
IfxAsclin_enableRxFifoInlet(g_asclinRegs, TRUE);
|
||||
IfxAsclin_enableTxFifoOutlet(g_asclinRegs, TRUE);
|
||||
|
||||
IfxAsclin_flushRxFifo(g_asclinRegs);
|
||||
IfxAsclin_flushTxFifo(g_asclinRegs);
|
||||
|
||||
return 0; /* Success */
|
||||
}
|
||||
|
||||
static int uartTx(const uint8_t c)
|
||||
{
|
||||
/* Write the data value to the ASCLIN peripheral's transmit FIFO. */
|
||||
/* Note: IfxAsclin_write8 takes a pointer */
|
||||
uint8 data_to_send = c;
|
||||
IfxAsclin_write8(g_asclinRegs, &data_to_send, 1);
|
||||
|
||||
/* Wait (poll) for the transmit FIFO to be empty */
|
||||
/* TODO: Consider adding a timeout mechanism here if necessary */
|
||||
while (IfxAsclin_getTxFifoFillLevel(g_asclinRegs) != 0) {
|
||||
/* Busy wait */
|
||||
}
|
||||
|
||||
return 0; /* Success */
|
||||
}
|
||||
|
||||
void uart_write(const char* buf, unsigned int sz)
|
||||
{
|
||||
static char rambuf[512];
|
||||
const static char lf = '\r';
|
||||
unsigned int i;
|
||||
|
||||
if (sz > sizeof(rambuf)) {
|
||||
sz = sizeof(rambuf);
|
||||
}
|
||||
memcpy(rambuf, buf, sz);
|
||||
buf = rambuf;
|
||||
|
||||
for (i = 0; i < sz; i++) {
|
||||
/* If newline character is detected, send carriage return first */
|
||||
if (buf[i] == '\n') {
|
||||
/* Send carriage return before newline */
|
||||
if (uartTx(lf) != 0) {
|
||||
/* Handle error if needed */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call uart_tx for each byte, which now polls until TX FIFO is empty */
|
||||
if (uartTx((uint8_t)buf[i]) != 0) {
|
||||
/* Handle error if needed */
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* No final wait needed here, as uart_tx waits after each byte */
|
||||
}
|
||||
|
||||
#endif /* DEBUG_UART */
|
||||
|
|
168
hal/hal.c
168
hal/hal.c
|
@ -33,12 +33,14 @@
|
|||
#ifndef TEST_ADDRESS
|
||||
#define TEST_SZ WOLFBOOT_SECTOR_SIZE
|
||||
#define TEST_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS
|
||||
#define TEST_ADDRESS_BANKA WOLFBOOT_PARTITION_BOOT_ADDRESS
|
||||
#define TEST_ADDRESS_BANKB WOLFBOOT_PARTITION_UPDATE_ADDRESS
|
||||
#endif
|
||||
|
||||
int hal_flash_test(void)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t i, len;
|
||||
uint32_t i;
|
||||
uint8_t* pagePtr = (uint8_t*)TEST_ADDRESS;
|
||||
static uint8_t pageData[TEST_SZ];
|
||||
|
||||
|
@ -60,8 +62,12 @@ int hal_flash_test(void)
|
|||
}
|
||||
|
||||
/* Write Page */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_write(TEST_ADDRESS, (uint8_t*)pageData, sizeof(pageData));
|
||||
hal_flash_lock();
|
||||
wolfBoot_printf("Write Page: Ret %d\n", ret);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
#endif /* !TEST_FLASH_READONLY */
|
||||
|
||||
/* Compare Page */
|
||||
|
@ -74,4 +80,164 @@ int hal_flash_test(void)
|
|||
wolfBoot_printf("Internal Flash Test Passed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef TEST_FLASH_READONLY
|
||||
int hal_flash_test_write_once(void)
|
||||
{
|
||||
uint8_t test_byte, expected_byte;
|
||||
unsigned int i, b;
|
||||
int ret = 0;
|
||||
|
||||
/* Erase the test sector */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_erase(TEST_ADDRESS, TEST_SZ);
|
||||
hal_flash_lock();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Erase Sector failed: Ret %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
expected_byte = 0xFF;
|
||||
/* For each bit in the byte (from LSB to MSB) */
|
||||
for (b = 0; b < 8; b++) {
|
||||
/* Toggle bit from 1 to 0 */
|
||||
test_byte = 0xFF & ~(1 << b);
|
||||
expected_byte &= ~(1 << b);
|
||||
|
||||
/* Write the data */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_write(TEST_ADDRESS, &test_byte, sizeof(test_byte));
|
||||
hal_flash_lock();
|
||||
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Write failed at bit %d: Ret %d\n", b, ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Verify the write by direct comparison */
|
||||
if (memcmp((void*)TEST_ADDRESS, &expected_byte, sizeof(expected_byte)) != 0) {
|
||||
wolfBoot_printf("Verification failed at byte %d, bit %d\n", i, b);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
wolfBoot_printf("Write-once test passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Test if unaligned write works. First test writing 1 bytes at SECTOR + 1.
|
||||
* Then test writing 2 bytes that span the sector boundary.
|
||||
*/
|
||||
int hal_flash_test_align(void)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t test_data_1 = 0xAA;
|
||||
uint8_t test_data_2[2] = {0xBB, 0xCC};
|
||||
uint8_t read_back[2];
|
||||
|
||||
/* erase both sectors */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_erase(TEST_ADDRESS, TEST_SZ * 2);
|
||||
hal_flash_lock();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Erase Sector failed: Ret %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write 1 byte at SECTOR + 1 */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_write(TEST_ADDRESS + 1, &test_data_1, 1);
|
||||
hal_flash_lock();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Unaligned write (1 byte) failed: Ret %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Verify 1 byte write */
|
||||
if (*(uint8_t*)(TEST_ADDRESS + 1) != test_data_1) {
|
||||
wolfBoot_printf("Unaligned write verification (1 byte) failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write 2 bytes spanning sector boundary */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_write(TEST_ADDRESS + TEST_SZ - 1, test_data_2, 2);
|
||||
hal_flash_lock();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Unaligned write (2 bytes) failed: Ret %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Verify 2 bytes write */
|
||||
memcpy(read_back, (void*)(TEST_ADDRESS + TEST_SZ - 1), 2);
|
||||
if (read_back[0] != test_data_2[0] || read_back[1] != test_data_2[1]) {
|
||||
wolfBoot_printf("Unaligned write verification (2 bytes) failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfBoot_printf("Unaligned write test passed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This test can be run only if swapping the flash do not reboot the board */
|
||||
#if defined(DUALBANK_SWAP) && !defined(TEST_FLASH_READONLY)
|
||||
int hal_flash_test_dualbank(void)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t i;
|
||||
uint8_t cur_fill = 0xb0;
|
||||
uint8_t new_fill = 0xf0;
|
||||
uint8_t fill;
|
||||
uint32_t pagePtr;
|
||||
|
||||
wolfBoot_printf("swap flash test at 0x%x\n", TEST_ADDRESS);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
fill = (i == 0) ? cur_fill : new_fill;
|
||||
pagePtr = (i == 0) ? TEST_ADDRESS_BANKA : TEST_ADDRESS_BANKB;
|
||||
|
||||
/* Erase sector */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_erase(pagePtr, WOLFBOOT_SECTOR_SIZE);
|
||||
hal_flash_lock();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Erase Sector failed: Ret %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Write Page */
|
||||
hal_flash_unlock();
|
||||
ret = hal_flash_write(pagePtr, (uint8_t*)&fill, sizeof(fill));
|
||||
hal_flash_lock();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("Write Page failed: Ret %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (*((uint8_t*)(TEST_ADDRESS_BANKA)) != cur_fill) {
|
||||
wolfBoot_printf("Bank A data mismatch: %x != %x\n", *((uint8_t*)TEST_ADDRESS_BANKA), cur_fill);
|
||||
return -1;
|
||||
}
|
||||
if (*((uint8_t*)(TEST_ADDRESS_BANKB)) != new_fill) {
|
||||
wolfBoot_printf("Bank B data mismatch: %x != %x\n", *((uint8_t*)TEST_ADDRESS_BANKB), new_fill);
|
||||
return -1;
|
||||
}
|
||||
hal_flash_dualbank_swap();
|
||||
|
||||
if (*((uint8_t*)(TEST_ADDRESS_BANKA)) != new_fill) {
|
||||
wolfBoot_printf("Bank A data mismatch after swap: %x != %x\n", *((uint8_t*)TEST_ADDRESS_BANKA), new_fill);
|
||||
return -1;
|
||||
}
|
||||
if (*((uint8_t*)(TEST_ADDRESS_BANKB)) != cur_fill) {
|
||||
wolfBoot_printf("Bank B data mismatch after swap: %x != %x\n", *((uint8_t*)TEST_ADDRESS_BANKB), cur_fill);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfBoot_printf("DUALBANK_SWAP test passed");
|
||||
return 0;
|
||||
}
|
||||
#endif /* DUALBANK_SWAP */
|
||||
|
||||
#endif /* TEST_FLASH */
|
||||
|
|
|
@ -0,0 +1,513 @@
|
|||
/* pic32c.c
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
#include "loader.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(TARGET_pic32cz)
|
||||
#include "pic32cz_registers.h"
|
||||
#elif defined(TARGET_pic32ck)
|
||||
#include "pic32ck_registers.h"
|
||||
#endif
|
||||
|
||||
#define FCW_CTRLA (*(volatile uint32_t *)(FCW_BASE + 0x00U))
|
||||
#define FCW_CTRLB (*(volatile uint32_t *)(FCW_BASE + 0x04U))
|
||||
#define FCW_MUTEX (*(volatile uint32_t *)(FCW_BASE + 0x08U))
|
||||
#define FCW_INTENCLR (*(volatile uint32_t *)(FCW_BASE + 0x0CU))
|
||||
#define FCW_INTENSET (*(volatile uint32_t *)(FCW_BASE + 0x10U))
|
||||
#define FCW_INTFLAG (*(volatile uint32_t *)(FCW_BASE + 0x14U))
|
||||
#define FCW_STATUS (*(volatile uint32_t *)(FCW_BASE + 0x18U))
|
||||
#define FCW_KEY (*(volatile uint32_t *)(FCW_BASE + 0x1CU))
|
||||
#define FCW_ADDR (*(volatile uint32_t *)(FCW_BASE + 0x20U))
|
||||
#define FCW_SRCADDR (*(volatile uint32_t *)(FCW_BASE + 0x24U))
|
||||
#define FCW_DATA ((volatile uint32_t *)(FCW_BASE + 0x28U))
|
||||
#define FCW_SWAP (*(volatile uint32_t *)(FCW_BASE + 0x48U))
|
||||
#define FCW_PWP ((volatile uint32_t *)(FCW_BASE + 0x4CU))
|
||||
#define FCW_LBWP (*(volatile uint32_t *)(FCW_BASE + 0x6CU))
|
||||
#define FCW_UBWP (*(volatile uint32_t *)(FCW_BASE + 0x70U))
|
||||
#define FCW_UOWP (*(volatile uint32_t *)(FCW_BASE + 0x74U))
|
||||
#define FCW_CWP (*(volatile uint32_t *)(FCW_BASE + 0x78U))
|
||||
#define FCW_HSMINTENCLR (*(volatile uint32_t *)(FCW_BASE + 0x80U))
|
||||
#define FCW_HSMINTENSET (*(volatile uint32_t *)(FCW_BASE + 0x84U))
|
||||
#define FCW_HSMINTFLAG (*(volatile uint32_t *)(FCW_BASE + 0x88U))
|
||||
#define FCW_HSMCWP (*(volatile uint32_t *)(FCW_BASE + 0x8CU))
|
||||
#define FCW_HSMLDAT ((volatile uint32_t *)(FCW_BASE + 0x90U))
|
||||
#define FCW_HSMUDAT ((volatile uint32_t *)(FCW_BASE + 0xB0U))
|
||||
|
||||
#define FCW_UNLOCK_WRKEY 0x91C32C01
|
||||
#define FCW_UNLOCK_SWAPKEY 0x91C32C02
|
||||
#define FCW_UNLOCK_CFGKEY 0x91C32C04
|
||||
#define FCW_OP_ERASE_SECTOR 0x4
|
||||
#define FCW_OP_QUAD_DOUBLE_WORD_WRITE 0x2
|
||||
#define FCW_OP_NOOP 0x0
|
||||
|
||||
#define FCW_BUSY_MASK (1 << 0)
|
||||
#define FCW_CTRLA_PREPG_BIT (1 << 7)
|
||||
#define FCW_CTRLA_NVMOP_MASK ((1 << 4) - 1)
|
||||
#define FCW_INTFLAG_DONE_BIT (1 << 0)
|
||||
#define FCW_SWAP_PFSWAP (1 << 8)
|
||||
|
||||
/*
|
||||
* bit 0 lock
|
||||
* bit [1:2] owner (01 = mcu)
|
||||
*/
|
||||
#define FCW_OWN_MCU (0x1 << 1)
|
||||
#define FCW_OWN_AND_LOCK 0x3
|
||||
#define FCW_MUTEX_LOCK_MASK 0x1
|
||||
|
||||
#define FCW_WRITE_SIZE (4 * 8)
|
||||
static uint32_t pic32_last_err = 0;
|
||||
|
||||
#define OSCCTRL_STATUS (*(volatile uint32_t *)(OSCCTRL_BASE + 0x10U))
|
||||
#define OSCCTRL_INTFLAG (*(volatile uint32_t *)(OSCCTRL_BASE + 0x0CU))
|
||||
#define OSCCTRL_PLL0CTRL (*(volatile uint32_t *)(OSCCTRL_BASE + 0x40U))
|
||||
#define OSCCTRL_PLL0FBDIV (*(volatile uint32_t *)(OSCCTRL_BASE + 0x44U))
|
||||
#define OSCCTRL_PLL0REFDIV (*(volatile uint32_t *)(OSCCTRL_BASE + 0x48U))
|
||||
#define OSCCTRL_PLL0POSTDIV0 (*(volatile uint32_t *)(OSCCTRL_BASE + 0x4CU))
|
||||
#define OSCCTRL_FRACDIV0 (*(volatile uint32_t *)(OSCCTRL_BASE + 0x6CU))
|
||||
#define OSCCTRL_SYNCBUSY (*(volatile uint32_t *)(OSCCTRL_BASE + 0x78U))
|
||||
|
||||
#define OSCCTRL_SYNCBUSY_FRACDIV0_MASK (1 << 6)
|
||||
|
||||
#define OSCCTRL_FRACDIV0_REMDIV_SHIFT (7)
|
||||
#define OSCCTRL_FRACDIV0_REMDIV(X) ((X) << OSCCTRL_FRACDIV0_REMDIV_SHIFT)
|
||||
#define OSCCTRL_FRACDIV0_INTDIV_SHIFT (16)
|
||||
#define OSCCTRL_FRACDIV0_INTDIV(X) ((X) << OSCCTRL_FRACDIV0_INTDIV_SHIFT)
|
||||
|
||||
#define OSCCTRL_PLL0POSTDIV0_EN (1 << 0x7)
|
||||
|
||||
#define OSCCTRL_PLL0CTRL_BWSEL_SHIFT (11)
|
||||
#define OSCCTRL_PLL0CTRL_BWSEL(X) ((X) << OSCCTRL_PLL0CTRL_BWSEL_SHIFT)
|
||||
#define OSCCTRL_PLL0CTRL_REFSEL_SHIFT (8)
|
||||
#define OSCCTRL_PLL0CTRL_REFSEL(X) ((X) << OSCCTRL_PLL0CTRL_REFSEL_SHIFT)
|
||||
#define OSCCTRL_PLL0CTRL_EN (1 << 1)
|
||||
|
||||
#define OSCCTRL_STATUS_PLL0LOCK (1 << 24)
|
||||
#define OSCCTRL_INTFLAG_PLL0LOCKR (1 << 24)
|
||||
|
||||
#define OSCCTRL_FRACDIV0 (*(volatile uint32_t *)(OSCCTRL_BASE + 0x6CU))
|
||||
#define OSCCTRL_FRACDIV0_REMDIV_SHIFT (7)
|
||||
#define OSCCTRL_FRACDIV0_REMDIV(X) ((X) << OSCCTRL_FRACDIV0_REMDIV_SHIFT)
|
||||
#define OSCCTRL_FRACDIV0_INTDIV_SHIFT (16)
|
||||
#define OSCCTRL_FRACDIV0_INTDIV(X) ((X) << OSCCTRL_FRACDIV0_INTDIV_SHIFT)
|
||||
|
||||
#define OSCCTRL_SYNCBUSY (*(volatile uint32_t *)(OSCCTRL_BASE + 0x78U))
|
||||
#define OSCCTRL_SYNCBUSY_FRACDIV0_MASK (1 << 6)
|
||||
|
||||
#define GCLK_CTRLA (*(volatile uint32_t *)(GCLK_BASE + 0x00U))
|
||||
#define GCLK_SYNCBUSY (*(volatile uint32_t *)(GCLK_BASE + 0x4U))
|
||||
#define GCLK_GENCTRL ((volatile uint32_t *)(GCLK_BASE + 0x20U))
|
||||
|
||||
#define GCLK_GENCTRL_SRC_PLL0 (6)
|
||||
#define GCLK_GENCTRL_GENEN (1 << 8)
|
||||
#define GCLK_GENCTRL_DIV_SHIFT (16)
|
||||
#define GCLK_GENCTRL_DIV(X) ((X) << GCLK_GENCTRL_DIV_SHIFT)
|
||||
#define GCLK_SYNCBUSY_GENCTRL0 (1 << 2)
|
||||
#define GCLK_CTRLA_SWRST (1)
|
||||
|
||||
#define MCLK_INTFLAG (*(volatile uint32_t *)(MCLK_BASE + 0x08U))
|
||||
#define MCLK_DIV0 (*(volatile uint32_t *)(MCLK_BASE + 0x0CU))
|
||||
#define MCLK_DIV1 (*(volatile uint32_t *)(MCLK_BASE + 0x10U))
|
||||
#define MCLK_INTFLAG_CKRDY (1)
|
||||
|
||||
void pic32_fcw_grab(void)
|
||||
{
|
||||
do {
|
||||
while (FCW_MUTEX & FCW_MUTEX_LOCK_MASK) {
|
||||
/* wait for ownership */
|
||||
|
||||
/* if mutex is locked by us, we can unlock it */
|
||||
if ((FCW_MUTEX & FCW_OWN_MCU) == FCW_OWN_MCU) {
|
||||
FCW_MUTEX = FCW_OWN_MCU;
|
||||
}
|
||||
}
|
||||
FCW_MUTEX = FCW_OWN_AND_LOCK;
|
||||
} while (FCW_MUTEX != FCW_OWN_AND_LOCK);
|
||||
}
|
||||
|
||||
void pic32_fcw_release(void)
|
||||
{
|
||||
FCW_MUTEX = FCW_OWN_MCU;
|
||||
}
|
||||
|
||||
static void pic32_fcw_start_op(uint32_t op)
|
||||
{
|
||||
FCW_CTRLA = FCW_CTRLA_PREPG_BIT | (op & FCW_CTRLA_NVMOP_MASK);
|
||||
}
|
||||
|
||||
static uint32_t pic32_get_errs(void)
|
||||
{
|
||||
return FCW_INTFLAG;
|
||||
}
|
||||
|
||||
static void pic32_clear_errs(void)
|
||||
{
|
||||
FCW_INTFLAG = 0xffffffff;
|
||||
}
|
||||
|
||||
static void pic32_fcw_wait_complete(void)
|
||||
{
|
||||
while (FCW_STATUS & FCW_BUSY_MASK) {}
|
||||
}
|
||||
|
||||
static int pic32_write_dqword_aligned(uint32_t addr, const uint8_t *data)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t *_data = (uint32_t *)data;
|
||||
uint32_t err;
|
||||
|
||||
pic32_fcw_wait_complete();
|
||||
FCW_ADDR = addr;
|
||||
for (i = 0; i < 8; i++) {
|
||||
FCW_DATA[i] = _data[i];
|
||||
}
|
||||
FCW_KEY = FCW_UNLOCK_WRKEY;
|
||||
pic32_fcw_start_op(FCW_OP_QUAD_DOUBLE_WORD_WRITE);
|
||||
pic32_fcw_wait_complete();
|
||||
err = pic32_get_errs();
|
||||
pic32_last_err = err;
|
||||
err &= ~FCW_INTFLAG_DONE_BIT;
|
||||
pic32_clear_errs();
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pic32_addr_is_dqword_aligned(uint32_t addr)
|
||||
{
|
||||
return ((addr & 0x1F) == 0);
|
||||
}
|
||||
|
||||
static uint32_t pic32_addr_dqword_align(uint32_t addr)
|
||||
{
|
||||
return (addr & ~0x1F);
|
||||
}
|
||||
|
||||
static void pic32_copy_dqword(uint8_t *dst, uint32_t addr)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < FCW_WRITE_SIZE; i++) {
|
||||
dst[i] = *(volatile uint8_t *)(addr + i);
|
||||
}
|
||||
}
|
||||
|
||||
static int pic32_fcw_erase_sector(uint32_t addr)
|
||||
{
|
||||
uint32_t err;
|
||||
pic32_fcw_wait_complete();
|
||||
FCW_ADDR = addr;
|
||||
FCW_KEY = FCW_UNLOCK_WRKEY;
|
||||
pic32_fcw_start_op(FCW_OP_ERASE_SECTOR);
|
||||
pic32_fcw_wait_complete();
|
||||
err = pic32_get_errs();
|
||||
pic32_clear_errs();
|
||||
pic32_last_err = err;
|
||||
err &= ~FCW_INTFLAG_DONE_BIT;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pic32_delay_cnt(uint32_t ticks)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for (i = 0; i < ticks; i++) {
|
||||
__asm__("nop");
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t pic32_mask_zeros(uint8_t programmed, uint8_t to_program)
|
||||
{
|
||||
return to_program | (~programmed);
|
||||
}
|
||||
|
||||
int pic32_flash_write(uint32_t address, const uint8_t *data, int len)
|
||||
{
|
||||
uint8_t buff[FCW_WRITE_SIZE], curr[FCW_WRITE_SIZE];
|
||||
uint32_t _addr;
|
||||
uint8_t i;
|
||||
int ret;
|
||||
|
||||
while (len > 0) {
|
||||
if (!pic32_addr_is_dqword_aligned(address) || len < FCW_WRITE_SIZE) {
|
||||
_addr = pic32_addr_dqword_align(address);
|
||||
/* Setup an aligned buffer with the following rules:
|
||||
* - For addresses outside the writing range: 0xFF (no change)
|
||||
* - For addresses inside the writing range: data | !current_data
|
||||
*
|
||||
* This approach ensures we only flip bits from 1 to 0 when writing
|
||||
* without an erase operation. When the address is aligned and length
|
||||
* is at least WOLFBOOT_SECTOR_SIZE, an erase was already performed,
|
||||
* so we can write data directly.
|
||||
*/
|
||||
pic32_copy_dqword(curr, _addr);
|
||||
memset(buff, 0xff, FCW_WRITE_SIZE);
|
||||
i = address - _addr;
|
||||
for (; i < FCW_WRITE_SIZE && len > 0; i++, len--) {
|
||||
buff[i] = pic32_mask_zeros(curr[i], *data);
|
||||
data++;
|
||||
address++;
|
||||
}
|
||||
ret = pic32_write_dqword_aligned(_addr, buff);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
continue;
|
||||
}
|
||||
ret = pic32_write_dqword_aligned(address, data);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
address += FCW_WRITE_SIZE;
|
||||
data += FCW_WRITE_SIZE;
|
||||
len -= FCW_WRITE_SIZE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pic32_flash_erase(uint32_t addr, int len)
|
||||
{
|
||||
int err;
|
||||
|
||||
while (len > 0) {
|
||||
if (len < WOLFBOOT_SECTOR_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
err = pic32_fcw_erase_sector(addr);
|
||||
if (err != 0)
|
||||
return err;
|
||||
addr += WOLFBOOT_SECTOR_SIZE;
|
||||
len -= WOLFBOOT_SECTOR_SIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DUALBANK_SWAP
|
||||
|
||||
static int pic32_fcw_pfswap_get()
|
||||
{
|
||||
return !!(FCW_SWAP & FCW_SWAP_PFSWAP);
|
||||
}
|
||||
|
||||
static void pic32_fcw_pfswap_set(int sw)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = FCW_SWAP;
|
||||
reg &= FCW_SWAP_PFSWAP;
|
||||
if (sw)
|
||||
reg |= FCW_SWAP_PFSWAP;
|
||||
FCW_KEY = FCW_UNLOCK_SWAPKEY;
|
||||
FCW_SWAP = reg;
|
||||
}
|
||||
|
||||
void pic32_flash_dualbank_swap(void)
|
||||
{
|
||||
uint32_t sw;
|
||||
uint32_t reg;
|
||||
|
||||
pic32_fcw_wait_complete();
|
||||
sw = pic32_fcw_pfswap_get();
|
||||
pic32_fcw_pfswap_set(!sw);
|
||||
}
|
||||
#endif /* DUALBANK_SWAP */
|
||||
|
||||
void pic32_clock_fracdiv0_set(int intdiv, int remdiv)
|
||||
{
|
||||
OSCCTRL_FRACDIV0 =
|
||||
OSCCTRL_FRACDIV0_INTDIV(intdiv) | OSCCTRL_FRACDIV0_REMDIV(remdiv);
|
||||
|
||||
while (OSCCTRL_SYNCBUSY & OSCCTRL_SYNCBUSY_FRACDIV0_MASK) {}
|
||||
}
|
||||
|
||||
void pic32_clock_pll0_init(int refdiv, int fbdiv, int bw, int postdiv)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* configure pll0 */
|
||||
OSCCTRL_PLL0CTRL = 0;
|
||||
OSCCTRL_PLL0REFDIV = refdiv;
|
||||
OSCCTRL_PLL0FBDIV = fbdiv;
|
||||
|
||||
/* enable PLL0 output 0 divied by 3 (300Mhz) */
|
||||
OSCCTRL_PLL0POSTDIV0 = OSCCTRL_PLL0POSTDIV0_EN | postdiv;
|
||||
|
||||
reg = OSCCTRL_PLL0CTRL;
|
||||
/* set the bandwith value */
|
||||
reg |= OSCCTRL_PLL0CTRL_BWSEL(bw);
|
||||
reg |= OSCCTRL_PLL0CTRL_REFSEL(0x2);
|
||||
reg |= OSCCTRL_PLL0CTRL_EN;
|
||||
OSCCTRL_PLL0CTRL |= reg;
|
||||
|
||||
/* wait to the PLL to lock */
|
||||
#if defined(TARGET_pic32cz)
|
||||
while (!(OSCCTRL_STATUS & OSCCTRL_STATUS_PLL0LOCK)) {}
|
||||
#endif
|
||||
#if defined(TARGET_pic32ck)
|
||||
while (!(OSCCTRL_INTFLAG & OSCCTRL_INTFLAG_PLL0LOCKR)) {}
|
||||
#endif
|
||||
}
|
||||
|
||||
void pic32_clock_gclk_gen0(int mclk_div1, int cpudiv)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* setup clock division before changing the generator */
|
||||
if (mclk_div1 != 1)
|
||||
MCLK_DIV1 = mclk_div1;
|
||||
|
||||
while (!(MCLK_INTFLAG & MCLK_INTFLAG_CKRDY)) {}
|
||||
|
||||
GCLK_GENCTRL[0] =
|
||||
GCLK_GENCTRL_SRC_PLL0 | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_DIV(cpudiv);
|
||||
while (GCLK_SYNCBUSY & GCLK_SYNCBUSY_GENCTRL0) {}
|
||||
}
|
||||
|
||||
void pic32_clock_reset(void)
|
||||
{
|
||||
/* reset GCLK module */
|
||||
GCLK_CTRLA = GCLK_CTRLA_SWRST;
|
||||
|
||||
/* wait for the reset to complete */
|
||||
while (GCLK_CTRLA & GCLK_CTRLA_SWRST) {}
|
||||
|
||||
/* reset MCLK_DIV1 to reset value */
|
||||
MCLK_DIV1 = 1;
|
||||
while (!(MCLK_INTFLAG & MCLK_INTFLAG_CKRDY)) {}
|
||||
|
||||
/* turn off PLL0 */
|
||||
OSCCTRL_PLL0CTRL = 0;
|
||||
OSCCTRL_PLL0POSTDIV0 = 0x20202020;
|
||||
|
||||
/* reset PLL0 values */
|
||||
OSCCTRL_PLL0REFDIV = 0;
|
||||
OSCCTRL_PLL0FBDIV = 0;
|
||||
|
||||
/* reset the fracdiv0 to reset value */
|
||||
pic32_clock_fracdiv0_set(32, 0);
|
||||
}
|
||||
#if defined(TEST_FLASH)
|
||||
int hal_flash_test_align(void);
|
||||
int hal_flash_test_write_once(void);
|
||||
int hal_flash_test(void);
|
||||
int hal_flash_test_dualbank(void);
|
||||
void pic32_flash_test(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = hal_flash_test();
|
||||
if (ret != 0)
|
||||
wolfBoot_panic();
|
||||
ret = hal_flash_test_align();
|
||||
if (ret != 0)
|
||||
wolfBoot_panic();
|
||||
ret = hal_flash_test_write_once();
|
||||
if (ret != 0)
|
||||
wolfBoot_panic();
|
||||
#ifdef DUALBANK_SWAP
|
||||
ret = hal_flash_test_dualbank();
|
||||
if (ret != 0)
|
||||
wolfBoot_panic();
|
||||
#endif
|
||||
}
|
||||
#endif /* TEST_FLASH */
|
||||
|
||||
#ifdef TEST_CLOCK
|
||||
|
||||
/* SysTick registers and constants */
|
||||
#define SYSTICK_BASE (0xE000E010U)
|
||||
|
||||
#define SYSTICK_RVR_MASK (0x00FFFFFF)
|
||||
#define SYSTICK_CSR (*(volatile uint32_t *)(SYSTICK_BASE + 0x00U))
|
||||
#define SYSTICK_RVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x04U))
|
||||
#define SYSTICK_CVR (*(volatile uint32_t *)(SYSTICK_BASE + 0x08U))
|
||||
#define SYSTICK_CSR_ENABLE (1 << 0)
|
||||
#define SYSTICK_CSR_CLKSOURCE (1 << 2)
|
||||
#define SYSTICK_CSR_COUNTFLAG (1 << 16)
|
||||
|
||||
#if defined(TARGET_pic32ck)
|
||||
#define PORT_BASE (0x44801000U)
|
||||
#define LED_NO 25
|
||||
#elif defined(TARGET_pic32cz)
|
||||
#define PORT_BASE (0x44840000U)
|
||||
#define LED_NO 21
|
||||
#endif
|
||||
|
||||
#define PORTB_BASE (PORT_BASE + 0x80 * 1)
|
||||
#define PORTB_DIRSET (*(volatile uint32_t *)(PORTB_BASE + 0x08))
|
||||
#define PORTB_DIRSET_OUT(X) (1 << (X))
|
||||
#define PORTB_OUTTGL (*(volatile uint32_t *)(PORTB_BASE + 0x1C))
|
||||
#define PORTB_OUTTGL_PIN(X) (1 << (X))
|
||||
|
||||
static int systick_init_1ms(uint32_t cpu_freq)
|
||||
{
|
||||
/* Calculate the reload value for 1ms period */
|
||||
uint32_t reload_value = (cpu_freq / 1000) - 1;
|
||||
|
||||
/* Check if reload value fits in 24 bits */
|
||||
if (reload_value > SYSTICK_RVR_MASK) {
|
||||
return -1;
|
||||
}
|
||||
/* Set reload value */
|
||||
SYSTICK_RVR = reload_value;
|
||||
/* Clear current value */
|
||||
SYSTICK_CVR = 0;
|
||||
/* Configure SysTick: enable counter, no interrupt, use CPU clock */
|
||||
SYSTICK_CSR = SYSTICK_CSR_ENABLE | SYSTICK_CSR_CLKSOURCE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void systick_delay_ms(uint32_t ms)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < ms; i++) {
|
||||
/* Wait until COUNTFLAG is set */
|
||||
while (!(SYSTICK_CSR & SYSTICK_CSR_COUNTFLAG)) {
|
||||
/* Wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests clock configuration using SysTick. Initializes 1ms ticks,
|
||||
* toggles LED every 1s for 10s, then every 100ms for 2s.
|
||||
*/
|
||||
void pic32_clock_test(unsigned long cpu_freq)
|
||||
{
|
||||
int i;
|
||||
PORTB_DIRSET = PORTB_DIRSET_OUT(LED_NO);
|
||||
/* Initialize SysTick with 1ms period based on target frequency */
|
||||
if (systick_init_1ms(cpu_freq) != 0) {
|
||||
wolfBoot_panic();
|
||||
}
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
systick_delay_ms(1000);
|
||||
/* Wait for 1 second */
|
||||
PORTB_OUTTGL = PORTB_OUTTGL_PIN(LED_NO);
|
||||
}
|
||||
/* end test by fast toggling */
|
||||
for (i = 0; i < 20; i++) {
|
||||
systick_delay_ms(100);
|
||||
/* Wait for 1 second */
|
||||
PORTB_OUTTGL = PORTB_OUTTGL_PIN(LED_NO);
|
||||
}
|
||||
}
|
||||
#endif /* TEST_CLOCK */
|
|
@ -0,0 +1,46 @@
|
|||
/* pic32c.h
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#ifndef PIC32C_H
|
||||
#define PIC32C_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(TEST_FLASH)
|
||||
void pic32_flash_test(void);
|
||||
#endif
|
||||
|
||||
#if defined(DUALBANK_SWAP)
|
||||
void pic32_flash_dualbank_swap(void);
|
||||
#endif
|
||||
|
||||
void pic32_fcw_grab(void);
|
||||
void pic32_fcw_release(void);
|
||||
int pic32_flash_erase(uint32_t addr, int len);
|
||||
int pic32_flash_write(uint32_t address, const uint8_t *data, int len);
|
||||
void pic32_clock_pll0_init(int refdiv, int fbdiv, int bw, int postdiv);
|
||||
void pic32_clock_fracdiv0_set(int intdiv, int remdiv);
|
||||
void pic32_clock_gclk_gen0(int mclk_div1, int cpudiv);
|
||||
void pic32_clock_reset(void);
|
||||
#if defined(TEST_CLOCK)
|
||||
void pic32_clock_test(unsigned long cpu_freq);
|
||||
#endif /* TEST_CLOCK */
|
||||
#endif /* PIC32C_H */
|
|
@ -0,0 +1,79 @@
|
|||
/* pic32ck.c
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include <hal/pic32c.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int hal_flash_write(uint32_t address, const uint8_t *data, int len)
|
||||
{
|
||||
return pic32_flash_write(address, data, len);
|
||||
}
|
||||
|
||||
void hal_flash_lock(void)
|
||||
{
|
||||
pic32_fcw_grab();
|
||||
}
|
||||
|
||||
void hal_flash_unlock(void)
|
||||
{
|
||||
pic32_fcw_release();
|
||||
}
|
||||
|
||||
int hal_flash_erase(uint32_t addr, int len)
|
||||
{
|
||||
return pic32_flash_erase(addr, len);
|
||||
}
|
||||
|
||||
#ifdef DUALBANK_SWAP
|
||||
void hal_flash_dualbank_swap(void)
|
||||
{
|
||||
pic32_flash_dualbank_swap();
|
||||
}
|
||||
#endif /* DUALBANK_SWAP */
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
#if defined(TEST_CLOCK)
|
||||
/* toggle led at 1hz for 10sec */
|
||||
pic32_clock_test(48000000U);
|
||||
#endif
|
||||
pic32_clock_fracdiv0_set(0, 0);
|
||||
pic32_clock_pll0_init(12, 240, 1, 8);
|
||||
pic32_clock_gclk_gen0(1, 1);
|
||||
#if defined(TEST_FLASH)
|
||||
pic32_flash_test();
|
||||
while (1) {}
|
||||
#endif
|
||||
#if defined(TEST_CLOCK)
|
||||
/* toggle led at 1hz */
|
||||
pic32_clock_test(120000000U);
|
||||
pic32_clock_reset();
|
||||
pic32_clock_test(48000000U);
|
||||
while (1) {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void hal_prepare_boot(void)
|
||||
{
|
||||
#ifndef TZEN
|
||||
pic32_clock_reset();
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
_start_text = .;
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_end_text = .;
|
||||
} > FLASH
|
||||
|
||||
.edidx :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.ARM.exidx*)
|
||||
} > FLASH
|
||||
|
||||
_stored_data = .;
|
||||
.data : AT (_stored_data)
|
||||
{
|
||||
_start_data = .;
|
||||
KEEP(*(.data*))
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.ramcode))
|
||||
. = ALIGN(4);
|
||||
_end_data = .;
|
||||
} > RAM
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_start_bss = .;
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_end_bss = .;
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
} > RAM
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@;
|
||||
_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@;
|
||||
_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@;
|
||||
_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@;
|
||||
|
||||
END_STACK = ORIGIN(RAM) + LENGTH(RAM);
|
|
@ -0,0 +1,30 @@
|
|||
/* pic32ck_registers.h
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#ifndef PIC32CK_REGISTERS_H
|
||||
#define PIC32CK_REGISTERS_H
|
||||
|
||||
#define FCW_BASE (0x44004000U)
|
||||
#define OSCCTRL_BASE (0x4400C000U)
|
||||
#define GCLK_BASE (0x44010000U)
|
||||
#define MCLK_BASE (0x44012000U)
|
||||
|
||||
#endif /* PIC32CK_REGISTERS_H */
|
|
@ -0,0 +1,108 @@
|
|||
/* pic32cz.c
|
||||
*
|
||||
* Copyright (C) 2021 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hal/pic32c.h>
|
||||
|
||||
#define SUPC_BASE (0x44020000U)
|
||||
#define SUPC_VREGCTRL (*(volatile uint32_t *)(SUPC_BASE + 0x1CU))
|
||||
#define SUPC_STATUS (*(volatile uint32_t *)(SUPC_BASE + 0x0CU))
|
||||
|
||||
#define SUPC_VREGCTRL_AVREGEN_PLLREG_EN (4)
|
||||
#define SUPC_VREGCTRL_AVREGEN_SHIFT (16)
|
||||
#define SUPC_STATUS_ADDVREGRDY_PLL (4)
|
||||
#define SUPC_STATUS_ADDVREGRDY_SHIFT (8)
|
||||
|
||||
static void pic32_supc_vreg_pll_enable(void)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
SUPC_VREGCTRL |= SUPC_VREGCTRL_AVREGEN_PLLREG_EN
|
||||
<< SUPC_VREGCTRL_AVREGEN_SHIFT;
|
||||
|
||||
/* wait for the vreg to be ready */
|
||||
while (!(SUPC_STATUS &
|
||||
(SUPC_STATUS_ADDVREGRDY_PLL << SUPC_STATUS_ADDVREGRDY_SHIFT))) {}
|
||||
}
|
||||
|
||||
#ifdef DUALBANK_SWAP
|
||||
void hal_flash_dualbank_swap(void)
|
||||
{
|
||||
pic32_flash_dualbank_swap();
|
||||
}
|
||||
#endif /* DUALBANK_SWAP */
|
||||
|
||||
int hal_flash_write(uint32_t address, const uint8_t *data, int len)
|
||||
{
|
||||
return pic32_flash_write(address, data, len);
|
||||
}
|
||||
|
||||
void hal_flash_unlock(void)
|
||||
{
|
||||
pic32_fcw_grab();
|
||||
}
|
||||
|
||||
void hal_flash_lock(void)
|
||||
{
|
||||
pic32_fcw_release();
|
||||
}
|
||||
|
||||
int hal_flash_erase(uint32_t addr, int len)
|
||||
{
|
||||
return pic32_flash_erase(addr, len);
|
||||
}
|
||||
|
||||
static void pic32_delay_cnt(uint32_t ticks)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for (i = 0; i < ticks; i++) {
|
||||
__asm__("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
#if defined(TEST_CLOCK)
|
||||
pic32_clock_test(48000000);
|
||||
#endif
|
||||
pic32_supc_vreg_pll_enable();
|
||||
pic32_clock_pll0_init(12, 225, 1, 3);
|
||||
pic32_clock_gclk_gen0(2, 1);
|
||||
pic32_delay_cnt(700);
|
||||
#if defined(TEST_FLASH)
|
||||
pic32_flash_test();
|
||||
while (1) {}
|
||||
#endif
|
||||
#if defined(TEST_CLOCK)
|
||||
pic32_clock_test(300000000);
|
||||
pic32_clock_reset();
|
||||
pic32_clock_test(48000000);
|
||||
while (1) {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void hal_prepare_boot(void)
|
||||
{
|
||||
pic32_clock_reset();
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = @BOOTLOADER_PARTITION_SIZE@
|
||||
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
_start_text = .;
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_end_text = .;
|
||||
} > FLASH
|
||||
|
||||
.edidx :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
*(.ARM.exidx*)
|
||||
} > FLASH
|
||||
|
||||
_stored_data = .;
|
||||
.data : AT (_stored_data)
|
||||
{
|
||||
_start_data = .;
|
||||
KEEP(*(.data*))
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.ramcode))
|
||||
. = ALIGN(4);
|
||||
_end_data = .;
|
||||
} > RAM
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_start_bss = .;
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_end_bss = .;
|
||||
__bss_end__ = .;
|
||||
_end = .;
|
||||
} > RAM
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
_wolfboot_partition_boot_address = @WOLFBOOT_PARTITION_BOOT_ADDRESS@;
|
||||
_wolfboot_partition_size = @WOLFBOOT_PARTITION_SIZE@;
|
||||
_wolfboot_partition_update_address = @WOLFBOOT_PARTITION_UPDATE_ADDRESS@;
|
||||
_wolfboot_partition_swap_address = @WOLFBOOT_PARTITION_SWAP_ADDRESS@;
|
||||
|
||||
END_STACK = ORIGIN(RAM) + LENGTH(RAM);
|
|
@ -0,0 +1,30 @@
|
|||
/* pic32cz_registers.h
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#ifndef PIC32CZ_REGISTERS_H
|
||||
#define PIC32CZ_REGISTERS_H
|
||||
|
||||
#define FCW_BASE (0x44002000U)
|
||||
#define OSCCTRL_BASE (0x44040000U)
|
||||
#define GCLK_BASE (0x44050000U)
|
||||
#define MCLK_BASE (0x44052000U)
|
||||
|
||||
#endif /* PIC32CZ_REGISTERS_H */
|
|
@ -54,29 +54,19 @@ static inline void hal_panic(void)
|
|||
extern flash_ctrl_t g_flash0_ctrl;
|
||||
extern flash_cfg_t g_flash0_cfg;
|
||||
|
||||
void hal_init(void)
|
||||
#if defined(WOLFBOOT_RENESAS_SCEPROTECT) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
static int sipInitDone = 0;
|
||||
int hal_renesas_init(void)
|
||||
{
|
||||
fsp_err_t err;
|
||||
uint32_t *pubkey;
|
||||
|
||||
if (sipInitDone)
|
||||
return 0;
|
||||
|
||||
#if defined(WOLFBOOT_RENESAS_SCEPROTECT) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
/* retrieve installed pubkey from flash */
|
||||
uint32_t *pubkey = keystore_get_buffer(0);
|
||||
#endif
|
||||
err = R_FLASH_HP_Close(&g_flash0_ctrl);
|
||||
err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);
|
||||
pubkey = keystore_get_buffer(0);
|
||||
|
||||
if(err != FSP_ERR_ALREADY_OPEN && err != FSP_SUCCESS){
|
||||
printf("ERROR: %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
|
||||
/* Setup Default Block 0 as Startup Setup Block */
|
||||
err = R_FLASH_HP_StartUpAreaSelect(&g_flash0_ctrl, FLASH_STARTUP_AREA_BLOCK0, true);
|
||||
if(err != FSP_SUCCESS){
|
||||
printf("ERROR: %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
#if defined(WOLFBOOT_RENESAS_SCEPROTECT) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
err = wolfCrypt_Init();
|
||||
if (err != 0) {
|
||||
printf("ERROR: wolfCrypt_Init %d\n", err);
|
||||
|
@ -93,12 +83,39 @@ void hal_init(void)
|
|||
pkInfo.keyflgs_crypt.bits.rsapub2048_installedkey_set = 1;
|
||||
pkInfo.keyflgs_crypt.bits.message_type = 1;
|
||||
err = wc_CryptoCb_CryptInitRenesasCmn(NULL, &pkInfo);
|
||||
|
||||
if (err < 0) {
|
||||
printf("ERROR: wc_CryptoCb_CryptInitRenesasCmn %d\n", err);
|
||||
hal_panic();
|
||||
return err;
|
||||
}
|
||||
sipInitDone = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
fsp_err_t err;
|
||||
|
||||
err = R_FLASH_HP_Close(&g_flash0_ctrl);
|
||||
err = R_FLASH_HP_Open(&g_flash0_ctrl, &g_flash0_cfg);
|
||||
|
||||
if (err != FSP_ERR_ALREADY_OPEN && err != FSP_SUCCESS){
|
||||
wolfBoot_printf("ERROR: %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
|
||||
/* Setup Default Block 0 as Startup Setup Block */
|
||||
err = R_FLASH_HP_StartUpAreaSelect(&g_flash0_ctrl, FLASH_STARTUP_AREA_BLOCK0, true);
|
||||
if (err != FSP_SUCCESS){
|
||||
wolfBoot_printf("ERROR: %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
#if defined(WOLFBOOT_RENESAS_SCEPROTECT) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
err = hal_renesas_init();
|
||||
if (err != 0) {
|
||||
wolfBoot_printf("ERROR: hal_renesas_init %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
151
hal/renesas-rx.c
151
hal/renesas-rx.c
|
@ -367,14 +367,92 @@ void hal_clk_init(void)
|
|||
PROTECT_ON(); /* write protect on */
|
||||
}
|
||||
|
||||
void hal_init(void)
|
||||
#if defined(WOLFBOOT_RENESAS_TSIP) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
static int sipInitDone = 0;
|
||||
int hal_renesas_init(void)
|
||||
{
|
||||
#if defined(WOLFBOOT_RENESAS_TSIP) && \
|
||||
!defined(WOLFBOOT_RENESAS_APP)
|
||||
int err;
|
||||
uint32_t key_type = 0;
|
||||
int tsip_key_type = -1;
|
||||
/* This structure is generated using Renesas Security Key Management Tool
|
||||
* See docs/Renesas.md */
|
||||
struct enc_pub_key *encrypted_user_key_data;
|
||||
|
||||
if (sipInitDone)
|
||||
return 0;
|
||||
|
||||
err = wolfCrypt_Init();
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* retrive installed pubkey data from flash */
|
||||
encrypted_user_key_data = (struct enc_pub_key*)keystore_get_buffer(0);
|
||||
|
||||
key_type = keystore_get_key_type(0);
|
||||
switch (key_type) {
|
||||
case AUTH_KEY_RSA2048:
|
||||
tsip_key_type = TSIP_KEY_TYPE_RSA2048;
|
||||
break;
|
||||
case AUTH_KEY_RSA3072:
|
||||
tsip_key_type = TSIP_KEY_TYPE_RSA3072;
|
||||
break;
|
||||
case AUTH_KEY_RSA4096:
|
||||
tsip_key_type = TSIP_KEY_TYPE_RSA4096;
|
||||
break;
|
||||
case AUTH_KEY_ECC256:
|
||||
tsip_key_type = TSIP_KEY_TYPE_ECDSAP256;
|
||||
break;
|
||||
case AUTH_KEY_ECC384:
|
||||
tsip_key_type = TSIP_KEY_TYPE_ECDSAP384;
|
||||
break;
|
||||
case AUTH_KEY_ECC521:
|
||||
case AUTH_KEY_ED25519:
|
||||
case AUTH_KEY_ED448:
|
||||
default:
|
||||
tsip_key_type = -1;
|
||||
break;
|
||||
}
|
||||
if (tsip_key_type == -1) {
|
||||
wolfBoot_printf("key type (%d) not supported\n", key_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Load encrypted UFPK (User Factory Programming Key) */
|
||||
tsip_inform_user_keys_ex(
|
||||
(byte*)&encrypted_user_key_data->wufpk,
|
||||
(byte*)&encrypted_user_key_data->initial_vector,
|
||||
(byte*)&encrypted_user_key_data->encrypted_user_key,
|
||||
0/* dummy */
|
||||
);
|
||||
|
||||
/* Load a wrapped public key into TSIP */
|
||||
if (tsip_use_PublicKey_buffer_crypt(&pkInfo,
|
||||
(const char*)&encrypted_user_key_data->encrypted_user_key,
|
||||
sizeof(encrypted_user_key_data->encrypted_user_key),
|
||||
tsip_key_type) != 0) {
|
||||
wolfBoot_printf("ERROR tsip_use_PublicKey_buffer\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Init Crypt Callback */
|
||||
pkInfo.sign_hash_type = sha256_mac; /* TSIP does not support SHA2-384/512 */
|
||||
pkInfo.keyflgs_crypt.bits.message_type = 1;
|
||||
err = wc_CryptoCb_CryptInitRenesasCmn(NULL, &pkInfo);
|
||||
if (err < 0) {
|
||||
wolfBoot_printf("ERROR: wc_CryptoCb_CryptInitRenesasCmn %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
sipInitDone = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif /* TSIP */
|
||||
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
#if defined(WOLFBOOT_RENESAS_TSIP) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
int err;
|
||||
#endif
|
||||
|
||||
/* For CCRX, mcu_clock_setup() in resetprg.c will set up clocks. */
|
||||
|
@ -393,72 +471,13 @@ void hal_init(void)
|
|||
|
||||
hal_flash_init();
|
||||
|
||||
#if defined(WOLFBOOT_RENESAS_TSIP) && \
|
||||
!defined(WOLFBOOT_RENESAS_APP)
|
||||
err = wolfCrypt_Init();
|
||||
#if defined(WOLFBOOT_RENESAS_TSIP) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
err = hal_renesas_init();
|
||||
if (err != 0) {
|
||||
wolfBoot_printf("ERROR: wolfCrypt_Init %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
|
||||
/* retrive installed pubkey data from flash */
|
||||
encrypted_user_key_data = (struct enc_pub_key*)keystore_get_buffer(0);
|
||||
|
||||
key_type = keystore_get_key_type(0);
|
||||
switch (key_type) {
|
||||
case AUTH_KEY_RSA2048:
|
||||
tsip_key_type = TSIP_RSA2048;
|
||||
break;
|
||||
case AUTH_KEY_RSA3072:
|
||||
tsip_key_type = TSIP_RSA3072;
|
||||
break;
|
||||
case AUTH_KEY_RSA4096:
|
||||
tsip_key_type = TSIP_RSA4096;
|
||||
break;
|
||||
case AUTH_KEY_ECC256:
|
||||
tsip_key_type = TSIP_ECCP256;
|
||||
break;
|
||||
case AUTH_KEY_ECC384:
|
||||
tsip_key_type = TSIP_ECCP384;
|
||||
break;
|
||||
case AUTH_KEY_ECC521:
|
||||
case AUTH_KEY_ED25519:
|
||||
case AUTH_KEY_ED448:
|
||||
default:
|
||||
tsip_key_type = -1;
|
||||
break;
|
||||
}
|
||||
if (tsip_key_type == -1) {
|
||||
wolfBoot_printf("key type (%d) not supported\n", key_type);
|
||||
wolfBoot_printf("ERROR: hal_renesas_init %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
|
||||
/* Load encrypted UFPK (User Factory Programming Key) */
|
||||
tsip_inform_user_keys_ex(
|
||||
(byte*)&encrypted_user_key_data->wufpk,
|
||||
(byte*)&encrypted_user_key_data->initial_vector,
|
||||
(byte*)&encrypted_user_key_data->encrypted_user_key,
|
||||
0/* dummy */
|
||||
);
|
||||
|
||||
/* Load a wrapped public key into TSIP */
|
||||
if (tsip_use_PublicKey_buffer_crypt(&pkInfo,
|
||||
(const char*)&encrypted_user_key_data->encrypted_user_key,
|
||||
sizeof(encrypted_user_key_data->encrypted_user_key),
|
||||
tsip_key_type) != 0) {
|
||||
wolfBoot_printf("ERROR tsip_use_PublicKey_buffer\n");
|
||||
hal_panic();
|
||||
}
|
||||
|
||||
/* Init Crypt Callback */
|
||||
pkInfo.sign_hash_type = sha256_mac; /* TSIP does not support SHA2-384/512 */
|
||||
pkInfo.keyflgs_crypt.bits.message_type = 1;
|
||||
err = wc_CryptoCb_CryptInitRenesasCmn(NULL, &pkInfo);
|
||||
if (err < 0) {
|
||||
wolfBoot_printf("ERROR: wc_CryptoCb_CryptInitRenesasCmn %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
#endif /* TSIP */
|
||||
#endif
|
||||
}
|
||||
|
||||
void hal_prepare_boot(void)
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "wolfssl/wolfcrypt/wc_port.h"
|
||||
#include "wolfssl/wolfcrypt/port/Renesas/renesas-fspsm-crypt.h"
|
||||
#include "wolfssl/wolfcrypt/port/Renesas/renesas-fspsm-types.h"
|
||||
|
||||
|
||||
FSPSM_ST pkInfo;
|
||||
uint8_t wrapped_public_key[RSIP_BYTE_SIZE_WRAPPED_KEY_VALUE_RSA_2048_PUBLIC];
|
||||
rsip_wrapped_key_t *p_wrapped_public_key = (rsip_wrapped_key_t *) wrapped_public_key;
|
||||
|
@ -125,20 +125,22 @@ void ext_flash_unlock(void)
|
|||
|
||||
#endif
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
|
||||
#if defined(WOLFBOOT_RENESAS_RSIP) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
|
||||
static int sipInitDone = 0;
|
||||
int hal_renesas_init(void)
|
||||
{
|
||||
fsp_err_t err;
|
||||
int ret;
|
||||
rsa_public_t rsip_pub_key;
|
||||
const size_t key_size = sizeof(rsip_pub_key);
|
||||
|
||||
err = wolfCrypt_Init();
|
||||
if (err != 0) {
|
||||
printf("ERROR: wolfCrypt_Init %d\n", err);
|
||||
hal_panic();
|
||||
if (sipInitDone)
|
||||
return 0;
|
||||
|
||||
ret = wolfCrypt_Init();
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("ERROR: wolfCrypt_Init %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* copy the key from ext flash to RAM */
|
||||
|
@ -146,8 +148,8 @@ void hal_init(void)
|
|||
(uint8_t*)RENESAS_RSIP_INSTALLEDKEY_RAM_ADDR, key_size);
|
||||
if (ret != key_size){
|
||||
wolfBoot_printf("Error reading public key at %lx\n",
|
||||
RENESAS_RSIP_INSTALLEDKEY_FLASH_ADDR);
|
||||
hal_panic();
|
||||
RENESAS_RSIP_INSTALLEDKEY_FLASH_ADDR);
|
||||
return -1;
|
||||
}
|
||||
/* import enrypted key */
|
||||
XMEMCPY(&rsip_pub_key, (const void*)RENESAS_RSIP_INSTALLEDKEY_RAM_ADDR, key_size);
|
||||
|
@ -166,12 +168,23 @@ void hal_init(void)
|
|||
pkInfo.keyflgs_crypt.bits.message_type = 1;
|
||||
pkInfo.hash_type = RSIP_HASH_TYPE_SHA256;
|
||||
err = wc_CryptoCb_CryptInitRenesasCmn(NULL, &pkInfo);
|
||||
|
||||
if (err < 0) {
|
||||
wolfBoot_printf("ERROR: wc_CryptoCb_CryptInitRenesasCmn %d\n", err);
|
||||
return err;
|
||||
}
|
||||
sipInitDone = 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void hal_init(void)
|
||||
{
|
||||
#if defined(WOLFBOOT_RENESAS_RSIP) && !defined(WOLFBOOT_RENESAS_APP)
|
||||
int err = hal_renesas_init();
|
||||
if (err != 0) {
|
||||
printf("ERROR: hal_renesas_init %d\n", err);
|
||||
hal_panic();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#include "target.h"
|
||||
#include "printf.h"
|
||||
|
||||
#ifdef WOLFBOOT_ELF_SCATTERED
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
#include "elf.h"
|
||||
#endif
|
||||
|
||||
|
@ -100,6 +100,9 @@ const int hsmClientKeyIdPubKey = 0xFF;
|
|||
const int hsmClientDevIdCrypt = WH_DEV_ID;
|
||||
const int hsmClientKeyIdCrypt = 0xFF;
|
||||
#endif
|
||||
#ifdef WOLFBOOT_CERT_CHAIN_VERIFY
|
||||
const whNvmId hsmClientNvmIdCertRootCA = 1;
|
||||
#endif
|
||||
|
||||
int hal_hsm_init_connect(void);
|
||||
int hal_hsm_disconnect(void);
|
||||
|
@ -355,7 +358,7 @@ void do_boot(const uint32_t *app_offset)
|
|||
main = (main_entry)((uint8_t*)pSymbolAddress + epc->entryoff);
|
||||
main(main_argc, main_argv, NULL, NULL);
|
||||
|
||||
#elif defined (WOLFBOOT_ELF_SCATTERED)
|
||||
#elif defined (WOLFBOOT_ELF_FLASH_SCATTER)
|
||||
uint8_t *entry_point = (sim_ram_base + (unsigned long)app_offset);
|
||||
printf("entry point: %p\n", entry_point);
|
||||
printf("app offset: %p\n", app_offset);
|
||||
|
@ -365,7 +368,7 @@ void do_boot(const uint32_t *app_offset)
|
|||
|
||||
/* TODO: call main ! */
|
||||
/* main(main_argc, main_argv); */
|
||||
wolfBoot_printf("Simulator for ELF_SCATTERED image not implemented yet. Exiting...\n");
|
||||
wolfBoot_printf("Simulator for ELF_FLASH_SCATTER image not implemented yet. Exiting...\n");
|
||||
exit(0);
|
||||
#else
|
||||
char *envp[1] = {NULL};
|
||||
|
|
|
@ -168,9 +168,7 @@ typedef struct elf64_program_header {
|
|||
typedef int (*elf_mmu_map_cb)(uint64_t, uint64_t, uint32_t);
|
||||
int elf_load_image_mmu(uint8_t *image, uintptr_t *entry, elf_mmu_map_cb mmu_cb);
|
||||
int elf_load_image(uint8_t *image, uintptr_t *entry, int is_ext);
|
||||
int elf_store_image_scattered(const unsigned char *image, unsigned long *entry_out, int ext_flash);
|
||||
int elf_check_image_scattered(uint8_t part, unsigned long *entry_out);
|
||||
int elf_hdr_size(const unsigned char *ehdr);
|
||||
int64_t elf_hdr_pht_combined_size(const unsigned char* ehdr);
|
||||
int elf_open(const unsigned char *ehdr, int *is_elf32);
|
||||
|
||||
|
||||
|
|
|
@ -27,19 +27,19 @@
|
|||
#if defined(__WOLFBOOT) || defined(UNIT_TEST)
|
||||
|
||||
#include <stdint.h>
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/wolfcrypt/sha256.h>
|
||||
#include "wolfssl/wolfcrypt/settings.h"
|
||||
#include "wolfssl/wolfcrypt/sha256.h"
|
||||
|
||||
#include "target.h"
|
||||
#include "wolfboot/wolfboot.h"
|
||||
|
||||
#ifdef ENCRYPT_WITH_CHACHA
|
||||
#include <wolfssl/wolfcrypt/chacha.h>
|
||||
#include "wolfssl/wolfcrypt/chacha.h"
|
||||
#else
|
||||
#include <wolfssl/wolfcrypt/aes.h>
|
||||
#include "wolfssl/wolfcrypt/aes.h"
|
||||
#endif
|
||||
|
||||
#include <wolfssl/wolfcrypt/pwdbased.h>
|
||||
#include "wolfssl/wolfcrypt/pwdbased.h"
|
||||
|
||||
#ifdef ENCRYPT_WITH_CHACHA
|
||||
|
||||
|
@ -65,7 +65,7 @@ int aes_init(void);
|
|||
void aes_set_iv(uint8_t *nonce, uint32_t address);
|
||||
#endif /* ENCRYPT_WITH_CHACHA */
|
||||
|
||||
/* Internal read/write functions (not exported in the libwolfboot API) */
|
||||
/* external flash encryption read/write functions */
|
||||
int ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len);
|
||||
int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
#include "target.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* Architecture specific calls */
|
||||
#ifdef MMU
|
||||
|
@ -161,6 +162,10 @@ extern const int hsmClientKeyIdPubKey; /* KeyId for public key operations */
|
|||
#ifdef EXT_ENCRYPTED
|
||||
extern const int hsmClientKeyIdCrypt; /* KeyId for image (enc/dec)ryption */
|
||||
#endif
|
||||
#ifdef WOLFBOOT_CERT_CHAIN_VERIFY
|
||||
/* NvmId for trusted root CA certificate */
|
||||
extern const whNvmId hsmClientNvmIdCertRootCA;
|
||||
#endif
|
||||
|
||||
/* Implementation of functions provided by HAL */
|
||||
int hal_hsm_init_connect(void);
|
||||
|
|
|
@ -833,11 +833,17 @@ int wolfBoot_open_image_external(struct wolfBoot_image* img, uint8_t part, uint8
|
|||
int wolfBoot_open_image_address(struct wolfBoot_image* img, uint8_t* image);
|
||||
int wolfBoot_verify_integrity(struct wolfBoot_image *img);
|
||||
int wolfBoot_verify_authenticity(struct wolfBoot_image *img);
|
||||
int wolfBoot_get_partition_state(uint8_t part, uint8_t *st);
|
||||
int wolfBoot_set_partition_state(uint8_t part, uint8_t newst);
|
||||
int wolfBoot_get_update_sector_flag(uint16_t sector, uint8_t *flag);
|
||||
int wolfBoot_set_update_sector_flag(uint16_t sector, uint8_t newflag);
|
||||
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
/* Support for ELF scatter/gather format */
|
||||
int wolfBoot_load_flash_image_elf(int part, unsigned long* entry_out,
|
||||
int ext_flash);
|
||||
int wolfBoot_check_flash_image_elf(uint8_t part, unsigned long* entry_out);
|
||||
#endif
|
||||
|
||||
uint8_t* wolfBoot_peek_image(struct wolfBoot_image *img, uint32_t offset,
|
||||
uint32_t* sz);
|
||||
|
||||
|
@ -925,6 +931,9 @@ static inline int wb_flash_write_verify_word(struct wolfBoot_image *img,
|
|||
|
||||
#else
|
||||
|
||||
# define SWAP_EXT (0)
|
||||
# define BOOT_EXT (0)
|
||||
# define UPDATE_EXT (0)
|
||||
# define PART_IS_EXT(x) (0)
|
||||
# define PARTN_IS_EXT(x) (0)
|
||||
# define wb_flash_erase(im, of, siz) \
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
#define WOLFSSL_USER_MUTEX /* avoid wc_port.c wc_InitAndAllocMutex */
|
||||
#define WOLFCRYPT_ONLY
|
||||
#define SIZEOF_LONG_LONG 8
|
||||
#define HAVE_EMPTY_AGGREGATES 0
|
||||
#define HAVE_ANONYMOUS_INLINE_AGGREGATES 0
|
||||
|
||||
/* Stdlib Types */
|
||||
#define CTYPE_USER /* don't let wolfCrypt types.h include ctype.h */
|
||||
|
@ -111,12 +113,16 @@ extern int tolower(int c);
|
|||
# define FREESCALE_LTC_TFM
|
||||
# endif
|
||||
|
||||
|
||||
/* Some ECC options are disabled to reduce size */
|
||||
# if !defined(WOLFCRYPT_SECURE_MODE)
|
||||
# if !defined(WOLFBOOT_TPM)
|
||||
# define NO_ECC_SIGN
|
||||
# define NO_ECC_DHE
|
||||
/* For Renesas RX do not enable the misc.c constant time code
|
||||
* due to issue with 64-bit types */
|
||||
# if defined(__RX__)
|
||||
# define WOLFSSL_NO_CT_OPS /* don't use constant time ops in misc.c */
|
||||
# endif
|
||||
# if !defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
|
||||
# define NO_ECC_EXPORT
|
||||
# define NO_ECC_KEY_EXPORT
|
||||
|
@ -499,6 +505,9 @@ extern int tolower(int c);
|
|||
#define WOLF_CRYPTO_CB_ONLY_ECC
|
||||
#define WOLF_CRYPTO_CB_ONLY_RSA
|
||||
#define WOLFSSL_NO_SW_MATH
|
||||
#define MAX_CRYPTO_DEVID_CALLBACKS 2
|
||||
#define WC_NO_DEFAULT_DEVID
|
||||
#define WOLFSSL_AES_SMALL_TABLES
|
||||
|
||||
#ifdef WOLFBOOT_RENESAS_TSIP
|
||||
#define WOLFSSL_RENESAS_TSIP
|
||||
|
@ -507,6 +516,10 @@ extern int tolower(int c);
|
|||
#define WOLFSSL_RENESAS_TSIP_CRYPTONLY
|
||||
#define NO_WOLFSSL_RENESAS_TSIP_CRYPT_HASH
|
||||
#define RENESAS_TSIP_INSTALLEDKEY_ADDR 0xFFFF0000
|
||||
#ifndef RENESAS_TSIP_INSTALLEDENCKEY_ADDR
|
||||
#define RENESAS_TSIP_INSTALLEDENCKEY_ADDR \
|
||||
(RENESAS_TSIP_INSTALLEDKEY_ADDR + 0x100)
|
||||
#endif
|
||||
#define ENCRYPTED_KEY_BYTE_SIZE ENC_PUB_KEY_SIZE
|
||||
#define RENESAS_DEVID 7890
|
||||
#endif
|
||||
|
@ -533,6 +546,7 @@ extern int tolower(int c);
|
|||
|
||||
#ifdef WOLFBOOT_ENABLE_WOLFHSM_CLIENT
|
||||
# define WOLF_CRYPTO_CB
|
||||
# undef HAVE_ANONYMOUS_INLINE_AGGREGATES
|
||||
# define HAVE_ANONYMOUS_INLINE_AGGREGATES 1
|
||||
# define WOLFSSL_KEY_GEN
|
||||
#endif /* WOLFBOOT_ENABLE_WOLFHSM_CLIENT */
|
||||
|
|
|
@ -79,7 +79,7 @@ extern "C" {
|
|||
#define HDR_SIGNATURE 0x20
|
||||
#define HDR_POLICY_SIGNATURE 0x21
|
||||
#define HDR_SECONDARY_SIGNATURE 0x22
|
||||
#define HDR_ELF_SCATTERED_HASH 0x23
|
||||
#define HDR_CERT_CHAIN 0x23
|
||||
#define HDR_PADDING 0xFF
|
||||
|
||||
/* Auth Key types */
|
||||
|
@ -162,9 +162,23 @@ extern "C" {
|
|||
|
||||
#if defined(__WOLFBOOT) || defined(UNIT_TEST_AUTH)
|
||||
|
||||
#include "wolfssl/wolfcrypt/settings.h"
|
||||
#include "wolfssl/wolfcrypt/visibility.h"
|
||||
#include "wolfssl/wolfcrypt/wc_port.h"
|
||||
#include "wolfssl/wolfcrypt/types.h"
|
||||
|
||||
#ifdef WOLFBOOT_RENESAS_TSIP
|
||||
/* Include these before any algorithm headers */
|
||||
#include "mcu/all/r_bsp_common.h"
|
||||
#include "r_bsp_config.h"
|
||||
#include "r_tsip_rx_if.h"
|
||||
#include "wolfssl/wolfcrypt/port/Renesas/renesas_tsip_types.h"
|
||||
#endif
|
||||
|
||||
|
||||
/* Hashing configuration */
|
||||
#if defined(WOLFBOOT_HASH_SHA256)
|
||||
# include "wolfssl/wolfcrypt/sha256.h"
|
||||
#include "wolfssl/wolfcrypt/sha256.h"
|
||||
# ifndef WOLFBOOT_SHA_BLOCK_SIZE
|
||||
# define WOLFBOOT_SHA_BLOCK_SIZE (256)
|
||||
# endif
|
||||
|
@ -179,7 +193,7 @@ extern "C" {
|
|||
typedef wc_Sha256 wolfBoot_hash_t;
|
||||
# define HDR_HASH HDR_SHA256
|
||||
#elif defined(WOLFBOOT_HASH_SHA384)
|
||||
# include "wolfssl/wolfcrypt/sha512.h"
|
||||
#include "wolfssl/wolfcrypt/sha512.h"
|
||||
# ifndef WOLFBOOT_SHA_BLOCK_SIZE
|
||||
# define WOLFBOOT_SHA_BLOCK_SIZE (256)
|
||||
# endif
|
||||
|
@ -194,9 +208,9 @@ extern "C" {
|
|||
typedef wc_Sha384 wolfBoot_hash_t;
|
||||
# define HDR_HASH HDR_SHA384
|
||||
#elif defined(WOLFBOOT_HASH_SHA3_384)
|
||||
# include "wolfssl/wolfcrypt/sha3.h"
|
||||
#include "wolfssl/wolfcrypt/sha3.h"
|
||||
# ifndef WOLFBOOT_SHA_BLOCK_SIZE
|
||||
# define WOLFBOOT_SHA_BLOCK_SIZE (128)
|
||||
# define WOLFBOOT_SHA_BLOCK_SIZE (256)
|
||||
# endif
|
||||
# define WOLFBOOT_SHA_HDR HDR_SHA3_384
|
||||
# define WOLFBOOT_SHA_DIGEST_SIZE (48)
|
||||
|
@ -223,7 +237,8 @@ extern "C" {
|
|||
|
||||
#endif
|
||||
|
||||
#if defined(__WOLFBOOT) || defined (__FLASH_OTP_PRIMER) || defined (UNIT_TEST_AUTH) || defined(WOLFBOOT_TPM)
|
||||
#if defined(__WOLFBOOT) || defined (__FLASH_OTP_PRIMER) || \
|
||||
defined (UNIT_TEST_AUTH) || defined(WOLFBOOT_TPM)
|
||||
|
||||
/* Authentication configuration */
|
||||
#if defined(WOLFBOOT_NO_SIGN)
|
||||
|
@ -326,6 +341,12 @@ extern "C" {
|
|||
#define FLASH_WORD_ERASED 0x00000000UL
|
||||
#endif
|
||||
|
||||
#ifdef __WOLFBOOT
|
||||
/* include after PART_* are defined */
|
||||
/* for wolfBoot_verify_integrity and wolfBoot_verify_authenticity */
|
||||
#include "image.h"
|
||||
#endif
|
||||
|
||||
void wolfBoot_update_trigger(void);
|
||||
void wolfBoot_success(void);
|
||||
uint32_t wolfBoot_image_size(uint8_t *image);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ea4c3db1e05b878f39c107b375c4c57ac93ab35a
|
||||
Subproject commit f76701294bb8be47c7a9364a1061483c9ed7b3af
|
|
@ -1 +1 @@
|
|||
Subproject commit b077c81eb635392e694ccedbab8b644297ec0285
|
||||
Subproject commit 2151a1b8a1f8f81c4dba985429d50b76db7307e5
|
51
options.mk
51
options.mk
|
@ -549,7 +549,10 @@ ifeq ($(ENCRYPT),1)
|
|||
endif
|
||||
|
||||
ifeq ($(EXT_FLASH),1)
|
||||
CFLAGS+= -D"EXT_FLASH=1" -D"PART_UPDATE_EXT=1" -D"PART_SWAP_EXT=1"
|
||||
CFLAGS+= -D"EXT_FLASH=1" -D"PART_UPDATE_EXT=1"
|
||||
ifeq ($(NO_SWAP_EXT),)
|
||||
CFLAGS+= -D"PART_SWAP_EXT=1"
|
||||
endif
|
||||
ifeq ($(NO_XIP),1)
|
||||
CFLAGS+=-D"PART_BOOT_EXT=1"
|
||||
endif
|
||||
|
@ -762,9 +765,7 @@ OBJS+=$(SECURE_OBJS)
|
|||
#
|
||||
ifeq ($(RAM_CODE),1)
|
||||
ifeq ($(ENCRYPT),1)
|
||||
ifneq ($(ENCRYPT_WITH_CHACHA),1)
|
||||
LSCRIPT_IN=NONE
|
||||
else
|
||||
ifeq ($(ENCRYPT_WITH_CHACHA),1)
|
||||
LSCRIPT_IN=hal/$(TARGET)_chacha_ram.ld
|
||||
endif
|
||||
endif
|
||||
|
@ -786,8 +787,8 @@ ifeq ($(ELF),1)
|
|||
ifneq ($(DEBUG_ELF),)
|
||||
CFLAGS+=-DDEBUG_ELF=$(DEBUG_ELF)
|
||||
endif
|
||||
ifeq ($(ELF_SCATTERED),1)
|
||||
CFLAGS+=-D"WOLFBOOT_ELF_SCATTERED=1"
|
||||
ifeq ($(ELF_FLASH_SCATTER),1)
|
||||
CFLAGS+=-D"WOLFBOOT_ELF_FLASH_SCATTER=1"
|
||||
endif
|
||||
|
||||
endif
|
||||
|
@ -907,5 +908,43 @@ ifeq ($(WOLFHSM_CLIENT),1)
|
|||
ifneq ($(WOLFHSM_CLIENT_LOCAL_KEYS),1)
|
||||
KEYGEN_OPTIONS += --nolocalkeys
|
||||
CFLAGS += -DWOLFBOOT_USE_WOLFHSM_PUBKEY_ID
|
||||
# big enough for cert chain
|
||||
CFLAGS += -DWOLFHSM_CFG_COMM_DATA_LEN=5000
|
||||
endif
|
||||
|
||||
# Ensure wolfHSM is configured to use certificate manager if we are
|
||||
# doing cert chain verification
|
||||
ifneq ($(CERT_CHAIN_VERIFY),)
|
||||
WOLFHSM_CLIENT_OBJS += \
|
||||
$(LIBDIR)/wolfHSM/src/wh_client_cert.o \
|
||||
$(LIBDIR)/wolfHSM/src/wh_message_cert.o
|
||||
CFLAGS += -DWOLFHSM_CFG_CERTIFICATE_MANAGER
|
||||
endif
|
||||
endif
|
||||
|
||||
# Cert chain verification options
|
||||
ifneq ($(CERT_CHAIN_VERIFY),)
|
||||
CFLAGS += -DWOLFBOOT_CERT_CHAIN_VERIFY
|
||||
# export the private key in DER format so it can be used with certificates
|
||||
KEYGEN_OPTIONS += --der
|
||||
ifneq ($(CERT_CHAIN_GEN),)
|
||||
# Use dummy cert chain file if not provided (needs to be generated when keys are generated)
|
||||
CERT_CHAIN_FILE = test-dummy-ca/raw-chain.der
|
||||
|
||||
# Set appropriate cert gen options based on sigalg
|
||||
ifeq ($(SIGN),ECC256)
|
||||
CERT_CHAIN_GEN_ALGO+=ecc256
|
||||
endif
|
||||
ifeq ($(SIGN),RSA2048)
|
||||
CERT_CHAIN_GEN_ALGO+=rsa2048
|
||||
endif
|
||||
ifeq ($(SIGN),RSA4096)
|
||||
CERT_CHAIN_GEN_ALGO+=rsa4096
|
||||
endif
|
||||
else
|
||||
ifeq ($(CERT_CHAIN_FILE),)
|
||||
$(error CERT_CHAIN_FILE must be specified when CERT_CHAIN_VERIFY is enabled and not using CERT_CHAIN_GEN)
|
||||
endif
|
||||
endif
|
||||
SIGN_OPTIONS += --cert-chain $(CERT_CHAIN_FILE)
|
||||
endif
|
||||
|
|
|
@ -43,7 +43,7 @@ struct BLOCK_HDR_PACKED block_hdr {
|
|||
#define BLOCK_HDR_SIZE (sizeof (struct block_hdr))
|
||||
|
||||
#if defined(EXT_ENCRYPTED) && defined(__WOLFBOOT)
|
||||
#include "encrypt.h"
|
||||
#include "image.h"
|
||||
#define ext_flash_check_write ext_flash_encrypt_write
|
||||
#define ext_flash_check_read ext_flash_decrypt_read
|
||||
#elif defined(__WOLFBOOT)
|
||||
|
|
170
src/elf.c
170
src/elf.c
|
@ -33,10 +33,6 @@
|
|||
#include "hal/nxp_ppc.h"
|
||||
#endif
|
||||
|
||||
#ifdef WOLFBOOT_ELF_SCATTERED
|
||||
#include "image.h"
|
||||
#endif
|
||||
|
||||
/* support for elf parsing debug printf */
|
||||
#if defined(DEBUG) || defined(ELF_PARSER)
|
||||
#if defined(DEBUG_ELF) && DEBUG_ELF == 0
|
||||
|
@ -48,6 +44,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
static int check_scatter_format(const unsigned char* ehdr, int is_elf32);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(MMU) || defined (WOLFBOOT_FSP) || defined (ARCH_PPC)
|
||||
/* Loader for elf32 or elf64 format program headers
|
||||
* Returns the entry point function
|
||||
|
@ -160,134 +162,66 @@ int elf_open(const unsigned char *ehdr, int *is_elf32)
|
|||
}
|
||||
wolfBoot_printf("ELF image found\n");
|
||||
*is_elf32 = !!(ident[ELF_CLASS_OFF] == ELF_CLASS_32);
|
||||
return 0;
|
||||
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
return check_scatter_format(ehdr, *is_elf32);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int elf_hdr_size(const unsigned char *ehdr)
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
/* Opens an elf file, also checking that the file is formatted correctly for
|
||||
* scattered loading. Returns 0 if the elf file is formatted correctly, -1
|
||||
* otherwise. */
|
||||
static int check_scatter_format(const unsigned char* ehdr, int is_elf32)
|
||||
{
|
||||
/* Check that the program header table immediately follows the elf header */
|
||||
if (is_elf32) {
|
||||
const elf32_header* elf32_hdr = (const elf32_header*)ehdr;
|
||||
/* For 32-bit ELF, program header table should start at offset equal to
|
||||
* sizeof(elf32_header) */
|
||||
if (elf32_hdr->ph_offset != sizeof(elf32_header)) {
|
||||
wolfBoot_printf("ELF32: Program header table not immediately after "
|
||||
"ELF header\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const elf64_header* elf64_hdr = (const elf64_header*)ehdr;
|
||||
/* For 64-bit ELF, program header table should start at offset equal to
|
||||
* sizeof(elf64_header) */
|
||||
if (elf64_hdr->ph_offset != sizeof(elf64_header)) {
|
||||
wolfBoot_printf("ELF64: Program header table not immediately after "
|
||||
"ELF header\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns the combined size of the elf header and program header table. This
|
||||
* assumes the program header table immediately follows the elf header. */
|
||||
int64_t elf_hdr_pht_combined_size(const unsigned char* ehdr)
|
||||
{
|
||||
int sz = 0;
|
||||
int is_elf32;
|
||||
if (elf_open(ehdr, &is_elf32) != 0)
|
||||
return -1;
|
||||
if (is_elf32) {
|
||||
const elf32_header *elf32_hdr = (const elf32_header *)ehdr;
|
||||
sz = sizeof(elf32_header);
|
||||
const elf32_header* elf32_hdr = (const elf32_header*)ehdr;
|
||||
sz = sizeof(elf32_header);
|
||||
sz += elf32_hdr->ph_entry_count * sizeof(elf32_program_header);
|
||||
} else {
|
||||
const elf64_header *elf64_hdr = (const elf64_header *)ehdr;
|
||||
sz = sizeof(elf64_header);
|
||||
}
|
||||
else {
|
||||
const elf64_header* elf64_hdr = (const elf64_header*)ehdr;
|
||||
sz = sizeof(elf64_header);
|
||||
sz += elf64_hdr->ph_entry_count * sizeof(elf64_program_header);
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
#if !defined(MMU) && !defined(WOLFBOOT_FSP) && !defined(ARCH_PPC) && defined (WOLFBOOT_ELF_SCATTERED)
|
||||
#endif /* WOLFBOOT_ELF_FLASH_SCATTER */
|
||||
|
||||
#ifdef ARCH_SIM
|
||||
# define BASE_OFF ARCH_FLASH_OFFSET
|
||||
#else
|
||||
# define BASE_OFF 0
|
||||
#endif
|
||||
|
||||
int elf_store_image_scattered(const unsigned char *hdr, unsigned long *entry_out, int ext_flash) {
|
||||
const unsigned char *image;
|
||||
int is_elf32;
|
||||
unsigned short entry_count;
|
||||
unsigned long entry_off;
|
||||
int i;
|
||||
image = hdr + IMAGE_HEADER_SIZE;
|
||||
if (elf_open(image, &is_elf32) != 0) {
|
||||
return -1;
|
||||
}
|
||||
if (is_elf32) {
|
||||
const elf32_header *eh;
|
||||
const elf32_program_header *ph;
|
||||
wolfBoot_printf("ELF image is 32 bit\n");
|
||||
|
||||
eh = (const elf32_header *)image;
|
||||
entry_count = eh->ph_entry_count;
|
||||
entry_off = eh->ph_offset;
|
||||
*entry_out = (unsigned long)eh->entry;
|
||||
|
||||
ph = (const elf32_program_header *)(image + entry_off);
|
||||
for (i = 0; i < entry_count; ++i) {
|
||||
unsigned long paddr;
|
||||
unsigned long filesz;
|
||||
unsigned long offset;
|
||||
|
||||
if (ph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
paddr = (unsigned long)ph[i].paddr;
|
||||
offset = (unsigned long)ph[i].offset;
|
||||
filesz = (unsigned long)ph[i].file_size;
|
||||
wolfBoot_printf("Writing section at address %lx offset %lx\n", paddr, offset);
|
||||
#ifdef EXT_FLASH
|
||||
if (ext_flash) {
|
||||
ext_flash_unlock();
|
||||
ext_flash_erase(paddr + BASE_OFF, filesz);
|
||||
ext_flash_write(paddr + BASE_OFF, image + offset, filesz);
|
||||
ext_flash_lock();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hal_flash_unlock();
|
||||
hal_flash_erase(paddr + BASE_OFF, filesz);
|
||||
hal_flash_write(paddr + BASE_OFF, image + offset, filesz);
|
||||
hal_flash_lock();
|
||||
}
|
||||
}
|
||||
} else { /* 64 bit ELF */
|
||||
const elf64_header *eh;
|
||||
const elf64_program_header *ph;
|
||||
wolfBoot_printf("ELF image is 64 bit\n");
|
||||
|
||||
eh = (const elf64_header *)image;
|
||||
entry_count = eh->ph_entry_count;
|
||||
entry_off = eh->ph_offset;
|
||||
*entry_out = (unsigned long)eh->entry;
|
||||
|
||||
ph = (const elf64_program_header *)(image + entry_off);
|
||||
for (i = 0; i < entry_count; ++i) {
|
||||
unsigned long paddr;
|
||||
unsigned long filesz;
|
||||
unsigned long offset;
|
||||
|
||||
if (ph[i].type != ELF_PT_LOAD)
|
||||
continue;
|
||||
paddr = (unsigned long)ph[i].paddr;
|
||||
offset = (unsigned long)ph[i].offset;
|
||||
filesz = (unsigned long)ph[i].file_size;
|
||||
wolfBoot_printf("Writing section at address %lx offset %lx\n", paddr, offset);
|
||||
#ifdef EXT_FLASH
|
||||
if (ext_flash) {
|
||||
ext_flash_unlock();
|
||||
ext_flash_erase(paddr + BASE_OFF, filesz);
|
||||
ext_flash_write(paddr + BASE_OFF, image + offset, filesz);
|
||||
ext_flash_lock();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hal_flash_unlock();
|
||||
hal_flash_erase(paddr + BASE_OFF, filesz);
|
||||
hal_flash_write(paddr + BASE_OFF, image + offset, filesz);
|
||||
hal_flash_lock();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* !defined(MMU) && !defined(WOLFBOOT_FSP) && !defined(ARCH_PPC) && defined (WOLFBOOT_ELF_SCATTERED) */
|
||||
|
||||
|
||||
int elf_load_image(uint8_t *image, uintptr_t *entry, int ext_flash)
|
||||
{
|
||||
#ifdef MMU
|
||||
return elf_load_image_mmu(image, entry, NULL);
|
||||
#else
|
||||
return elf_store_image_scattered(image, (unsigned long *)entry, ext_flash);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* WOLFBOOT_ELF */
|
||||
|
|
858
src/image.c
858
src/image.c
|
@ -53,7 +53,13 @@
|
|||
#endif
|
||||
|
||||
/* Globals */
|
||||
static uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE];
|
||||
static uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE] XALIGNED(4);
|
||||
|
||||
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY) && \
|
||||
defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
|
||||
static whKeyId g_certLeafKeyId = WH_KEYID_ERASED;
|
||||
static int g_leafKeyIdValid = 0;
|
||||
#endif
|
||||
|
||||
/* TPM based verify */
|
||||
#if defined(WOLFBOOT_TPM) && defined(WOLFBOOT_TPM_VERIFY)
|
||||
|
@ -241,7 +247,23 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot,
|
|||
const int point_sz = ECC_IMAGE_SIGNATURE_SIZE / 2;
|
||||
|
||||
/* Use the public key ID to verify the signature */
|
||||
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY)
|
||||
/* If using certificate chain verification and we have a verified leaf
|
||||
* key ID */
|
||||
if (g_leafKeyIdValid) {
|
||||
/* Use the leaf key ID from certificate verification */
|
||||
ret = wh_Client_EccSetKeyId(&ecc, g_certLeafKeyId);
|
||||
wolfBoot_printf(
|
||||
"Using leaf cert public key (ID: %08x) for ECC verification\n",
|
||||
(unsigned int)g_certLeafKeyId);
|
||||
}
|
||||
else {
|
||||
/* Default behavior: use the pre-configured public key ID */
|
||||
ret = wh_Client_EccSetKeyId(&ecc, hsmClientKeyIdPubKey);
|
||||
}
|
||||
#else
|
||||
ret = wh_Client_EccSetKeyId(&ecc, hsmClientKeyIdPubKey);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -273,6 +295,12 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot,
|
|||
img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, &verify_res,
|
||||
&ecc);
|
||||
}
|
||||
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY)
|
||||
if (g_leafKeyIdValid) {
|
||||
(void)wh_Client_KeyEvict(&hsmClientCtx, g_certLeafKeyId);
|
||||
g_leafKeyIdValid = 0;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
/* Import public key */
|
||||
ret = wc_ecc_import_unsigned(&ecc, pubkey, pubkey + point_sz, NULL,
|
||||
|
@ -400,7 +428,23 @@ static void wolfBoot_verify_signature_rsa(uint8_t key_slot,
|
|||
#if defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID)
|
||||
(void)key_slot;
|
||||
/* public key is stored on server at hsmClientKeyIdPubKey*/
|
||||
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY)
|
||||
/* If using certificate chain verification and we have a verified leaf key
|
||||
* ID */
|
||||
if (g_leafKeyIdValid) {
|
||||
/* Use the leaf key ID from certificate verification */
|
||||
ret = wh_Client_RsaSetKeyId(&rsa, g_certLeafKeyId);
|
||||
wolfBoot_printf(
|
||||
"Using leaf cert public key (ID: %08x) for RSA verification\n",
|
||||
(unsigned int)g_certLeafKeyId);
|
||||
}
|
||||
else {
|
||||
/* Default behavior: use the pre-configured public key ID */
|
||||
ret = wh_Client_RsaSetKeyId(&rsa, hsmClientKeyIdPubKey);
|
||||
}
|
||||
#else
|
||||
ret = wh_Client_RsaSetKeyId(&rsa, hsmClientKeyIdPubKey);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -426,6 +470,11 @@ static void wolfBoot_verify_signature_rsa(uint8_t key_slot,
|
|||
if (WH_ERROR_OK != wh_Client_KeyEvict(&hsmClientCtx, hsmKeyId)) {
|
||||
return;
|
||||
}
|
||||
#elif defined(WOLFBOOT_CERT_CHAIN_VERIFY)
|
||||
if (g_leafKeyIdValid) {
|
||||
(void)wh_Client_KeyEvict(&hsmClientCtx, g_certLeafKeyId);
|
||||
g_leafKeyIdValid = 0;
|
||||
}
|
||||
#endif /* !WOLFBOOT_USE_WOLFHSM_PUBKEY_ID */
|
||||
#else
|
||||
/* wolfCrypt software RSA verify */
|
||||
|
@ -644,7 +693,23 @@ static void wolfBoot_verify_signature_ml_dsa(uint8_t key_slot,
|
|||
#if defined WOLFBOOT_ENABLE_WOLFHSM_CLIENT && \
|
||||
defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID)
|
||||
/* Use key slot ID directly with wolfHSM */
|
||||
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY)
|
||||
/* If using certificate chain verification and we have a verified leaf key
|
||||
* ID */
|
||||
if (g_leafKeyIdValid) {
|
||||
/* Use the leaf key ID from certificate verification */
|
||||
ret = wh_Client_MlDsaSetKeyId(&ml_dsa, g_certLeafKeyId);
|
||||
wolfBoot_printf(
|
||||
"Using leaf cert public key (ID: %08x) for ML-DSA verification\n",
|
||||
(unsigned int)g_certLeafKeyId);
|
||||
}
|
||||
else {
|
||||
/* Default behavior: use the pre-configured public key ID */
|
||||
ret = wh_Client_MlDsaSetKeyId(&ml_dsa, hsmClientKeyIdPubKey);
|
||||
}
|
||||
#else
|
||||
ret = wh_Client_MlDsaSetKeyId(&ml_dsa, hsmClientKeyIdPubKey);
|
||||
#endif
|
||||
if (ret != 0) {
|
||||
wolfBoot_printf("error: wh_Client_MlDsaSetKeyId returned %d\n", ret);
|
||||
}
|
||||
|
@ -748,7 +813,7 @@ uint16_t wolfBoot_get_header(struct wolfBoot_image *img, uint16_t type,
|
|||
}
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
static uint8_t ext_hash_block[WOLFBOOT_SHA_BLOCK_SIZE];
|
||||
static uint8_t ext_hash_block[WOLFBOOT_SHA_BLOCK_SIZE] XALIGNED(4);
|
||||
#endif
|
||||
/**
|
||||
* @brief Get a block of data to be hashed.
|
||||
|
@ -772,7 +837,7 @@ static uint8_t *get_sha_block(struct wolfBoot_image *img, uint32_t offset)
|
|||
}
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
static uint8_t hdr_cpy[IMAGE_HEADER_SIZE];
|
||||
static uint8_t hdr_cpy[IMAGE_HEADER_SIZE] XALIGNED(4);
|
||||
static int hdr_cpy_done = 0;
|
||||
|
||||
/**
|
||||
|
@ -1327,283 +1392,548 @@ int wolfBoot_verify_integrity(struct wolfBoot_image *img)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WOLFBOOT_ELF_SCATTERED
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
#include "elf.h"
|
||||
|
||||
#define PADDING_BLOCK_SIZE 64
|
||||
|
||||
#ifdef ARCH_SIM
|
||||
#define BASE_OFF ARCH_FLASH_OFFSET
|
||||
#else
|
||||
#define BASE_OFF 0
|
||||
#endif
|
||||
|
||||
int elf_check_image_scattered(uint8_t part, unsigned long *entry_out)
|
||||
/* Maximum size of ELF header for any architecture */
|
||||
typedef union {
|
||||
elf32_header elf32;
|
||||
elf64_header elf64;
|
||||
} elfHeaderMaxBuf;
|
||||
|
||||
/*
|
||||
* Copies an arbitrary amount of data between two flash memory locations
|
||||
* (internal or external) using an intermediate RAM buffer.
|
||||
*/
|
||||
static int copy_flash_buffered(uintptr_t src_addr, uintptr_t dst_addr,
|
||||
size_t total_size, int is_src_ext,
|
||||
int is_dst_ext)
|
||||
{
|
||||
size_t bytes_copied = 0;
|
||||
|
||||
#ifndef BUFFER_DECLARED
|
||||
#define BUFFER_DECLARED
|
||||
static uint8_t buffer[FLASHBUFFER_SIZE] XALIGNED(4);
|
||||
#endif
|
||||
|
||||
#ifdef WOLFBOOT_FLASH_MULTI_SECTOR_ERASE
|
||||
/* Mass erase destination flash in one go before writing */
|
||||
#ifdef EXT_FLASH
|
||||
if (is_dst_ext) {
|
||||
ext_flash_unlock();
|
||||
ext_flash_erase(dst_addr, total_size);
|
||||
ext_flash_lock();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hal_flash_unlock();
|
||||
hal_flash_erase(dst_addr, total_size);
|
||||
hal_flash_lock();
|
||||
}
|
||||
#endif /* WOLFBOOT_FLASH_MULTI_SECTOR_ERASE */
|
||||
|
||||
/* Loop until all requested bytes are copied */
|
||||
while (bytes_copied < total_size) {
|
||||
/* Determine the size of the next chunk to copy */
|
||||
size_t remaining_bytes = total_size - bytes_copied;
|
||||
size_t chunk_size = (remaining_bytes > FLASHBUFFER_SIZE)
|
||||
? FLASHBUFFER_SIZE
|
||||
: remaining_bytes;
|
||||
|
||||
/* Read a chunk from the source flash into the RAM buffer */
|
||||
#ifdef EXT_FLASH
|
||||
if (is_src_ext) {
|
||||
ext_flash_unlock();
|
||||
ext_flash_read(src_addr + bytes_copied, buffer, chunk_size);
|
||||
ext_flash_lock();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
memcpy(buffer, (const void*)(src_addr + bytes_copied), chunk_size);
|
||||
}
|
||||
|
||||
/* Write the chunk from the RAM buffer to the destination flash */
|
||||
#ifdef EXT_FLASH
|
||||
if (is_dst_ext) {
|
||||
ext_flash_unlock();
|
||||
#ifndef WOLFBOOT_FLASH_MULTI_SECTOR_ERASE
|
||||
ext_flash_erase(dst_addr + bytes_copied, chunk_size);
|
||||
#endif
|
||||
ext_flash_write(dst_addr + bytes_copied, buffer, chunk_size);
|
||||
ext_flash_lock();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
hal_flash_unlock();
|
||||
#ifndef WOLFBOOT_FLASH_MULTI_SECTOR_ERASE
|
||||
hal_flash_erase(dst_addr + bytes_copied, chunk_size);
|
||||
#endif
|
||||
hal_flash_write(dst_addr + bytes_copied, buffer, chunk_size);
|
||||
hal_flash_lock();
|
||||
}
|
||||
|
||||
/* Update the count of bytes successfully copied */
|
||||
bytes_copied += chunk_size;
|
||||
}
|
||||
|
||||
/* All bytes copied successfully */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads data from a given wolfBoot partition's firmware image, properly
|
||||
* handling internal/external flash.
|
||||
*/
|
||||
static int read_flash_fwimage(struct wolfBoot_image* img, uint32_t offset,
|
||||
void* buffer, uint32_t size)
|
||||
{
|
||||
if (img == NULL || buffer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/* Prevent reading past the end of the image */
|
||||
if ((uint64_t)offset + size > img->fw_size) {
|
||||
wolfBoot_printf(
|
||||
"ERROR: read_flash_fwimage attempt to read past fw_size! "
|
||||
"Offset %lu, Size %u, TotalSize %lu\n",
|
||||
(unsigned long)offset, size, (unsigned long)img->fw_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
if (PART_IS_EXT(img)) {
|
||||
if (ext_flash_check_read((uintptr_t)img->fw_base + offset, buffer,
|
||||
size) < 0) {
|
||||
wolfBoot_printf(
|
||||
"ERROR: ext_flash_check_read failed at offset %lu, size %u\n",
|
||||
(unsigned long)offset, size);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Internal flash: Direct memory access */
|
||||
memcpy(buffer, (uint8_t*)img->fw_base + offset, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads data from a raw flash address (no offset) into a RAM buffer,
|
||||
* properly handling internal/external flash.
|
||||
*/
|
||||
static int read_flash_addr(void* src, void* buffer, uint32_t size, int src_ext)
|
||||
{
|
||||
if (src == NULL || buffer == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
if (src_ext) {
|
||||
if (ext_flash_check_read((uintptr_t)src, buffer, size) < 0) {
|
||||
wolfBoot_printf(
|
||||
"ERROR: ext_flash_check_read failed at address %p, size %u\n",
|
||||
src, size);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Internal flash: Direct memory access */
|
||||
memcpy(buffer, src, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hashes a chunk of the firmware image one SHA block at a time, properly
|
||||
* handling internal/external flash
|
||||
*/
|
||||
static int update_hash_flash_fwimg(wolfBoot_hash_t* ctx,
|
||||
struct wolfBoot_image* img, uint32_t offset,
|
||||
uint32_t size)
|
||||
{
|
||||
uint32_t current_offset = offset;
|
||||
uint32_t remaining_size = size;
|
||||
uint8_t read_buf[WOLFBOOT_SHA_BLOCK_SIZE] XALIGNED_STACK(4); /* Use local buffer */
|
||||
|
||||
while (remaining_size > 0) {
|
||||
uint32_t read_size = (remaining_size > WOLFBOOT_SHA_BLOCK_SIZE)
|
||||
? WOLFBOOT_SHA_BLOCK_SIZE
|
||||
: remaining_size;
|
||||
|
||||
if (read_flash_fwimage(img, current_offset, read_buf, read_size) != 0) {
|
||||
wolfBoot_printf("ERROR: Failed to read image data for hashing. "
|
||||
"Offset: %lu, Size: %u\n",
|
||||
(unsigned long)current_offset, read_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
update_hash(ctx, read_buf, read_size);
|
||||
|
||||
remaining_size -= read_size;
|
||||
current_offset += read_size;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hashes a chunk of flash memory at a given absolute address, reading one
|
||||
* SHA block at a time, properly handling internal/external flash
|
||||
*/
|
||||
static int update_hash_flash_addr(wolfBoot_hash_t* ctx, uintptr_t addr,
|
||||
uint32_t size, int src_ext)
|
||||
{
|
||||
uint8_t buffer[WOLFBOOT_SHA_BLOCK_SIZE] XALIGNED_STACK(4);
|
||||
uint32_t remaining_size = size;
|
||||
uintptr_t current_addr = addr;
|
||||
|
||||
while (remaining_size > 0) {
|
||||
uint32_t read_size = (remaining_size > WOLFBOOT_SHA_BLOCK_SIZE)
|
||||
? WOLFBOOT_SHA_BLOCK_SIZE
|
||||
: remaining_size;
|
||||
|
||||
if (read_flash_addr((void*)current_addr, buffer, read_size, src_ext) !=
|
||||
0) {
|
||||
wolfBoot_printf(
|
||||
"ERROR: Failed to read data from address %p, size %u\n",
|
||||
(void*)current_addr, read_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
update_hash(ctx, buffer, read_size);
|
||||
|
||||
remaining_size -= read_size;
|
||||
current_addr += read_size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wolfBoot_check_flash_image_elf(uint8_t part, unsigned long* entry_out)
|
||||
{
|
||||
/* Open the partition containing the image */
|
||||
int is_elf32;
|
||||
struct wolfBoot_image boot;
|
||||
uint8_t *elf_h, *p;
|
||||
int elf_hdr_sz = 0;
|
||||
int len;
|
||||
int is_elf32;
|
||||
unsigned short entry_count;
|
||||
unsigned short entry_size;
|
||||
unsigned long entry_off;
|
||||
long final_offset = -1;
|
||||
uint8_t calc_digest[WOLFBOOT_SHA_DIGEST_SIZE];
|
||||
uint8_t *exp_digest;
|
||||
int stored_sha_len;
|
||||
int i;
|
||||
uint8_t padding_block[PADDING_BLOCK_SIZE];
|
||||
int entry_out_set = 0;
|
||||
uint8_t * elf_h;
|
||||
size_t elf_hdr_sz = 0;
|
||||
uint32_t len;
|
||||
uint16_t entry_count = 0;
|
||||
size_t entry_off = 0;
|
||||
size_t ph_size = 0;
|
||||
size_t current_ph_offset = 0;
|
||||
int64_t final_offset = -1;
|
||||
uint8_t calc_digest[WOLFBOOT_SHA_DIGEST_SIZE] XALIGNED_STACK(4);
|
||||
uint8_t* exp_digest;
|
||||
int32_t stored_sha_len;
|
||||
int i;
|
||||
int32_t entry_out_set = 0;
|
||||
uint8_t elfHdrBuf[sizeof(elfHeaderMaxBuf)];
|
||||
uint8_t ph_buf[sizeof(elf64_program_header)]; /* Buffer for current PH */
|
||||
uint8_t ph_next_buf[sizeof(elf64_program_header)]; /* Buffer for next PH */
|
||||
|
||||
|
||||
|
||||
wolfBoot_hash_t ctx;
|
||||
if (wolfBoot_open_image(&boot, part) < 0)
|
||||
if (wolfBoot_open_image(&boot, part) < 0) {
|
||||
return -1;
|
||||
p = get_img_hdr(&boot);
|
||||
}
|
||||
|
||||
/* Initialize hash, feed the manifest header to it */
|
||||
if (header_hash(&ctx, &boot) < 0)
|
||||
if (header_hash(&ctx, &boot) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
stored_sha_len = get_header(&boot, HDR_HASH, &exp_digest);
|
||||
if (stored_sha_len != WOLFBOOT_SHA_DIGEST_SIZE)
|
||||
if (stored_sha_len != WOLFBOOT_SHA_DIGEST_SIZE) {
|
||||
return -1;
|
||||
|
||||
/* Get the elf header size */
|
||||
elf_h = p + IMAGE_HEADER_SIZE;
|
||||
|
||||
if (elf_open(elf_h, &is_elf32) < 0)
|
||||
return -1;
|
||||
|
||||
elf_hdr_sz = elf_hdr_size(elf_h);
|
||||
wolfBoot_printf("Elf header size: %d\n", elf_hdr_sz);
|
||||
|
||||
memset(padding_block, 0, PADDING_BLOCK_SIZE);
|
||||
|
||||
/* Feed the elf header to the hash function */
|
||||
len = elf_hdr_sz;
|
||||
p = elf_h;
|
||||
while (len > 0) {
|
||||
if (len > WOLFBOOT_SHA_BLOCK_SIZE) {
|
||||
update_hash(&ctx, p, WOLFBOOT_SHA_BLOCK_SIZE);
|
||||
len -= WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, p, len);
|
||||
break;
|
||||
}
|
||||
p += WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
}
|
||||
wolfBoot_printf("Hashed ELF header.\n");
|
||||
|
||||
/* Feed the program headers to the hash function */
|
||||
/* Get the elf header from the image into a local buffer. We may overread
|
||||
* the buffer depending on architecture */
|
||||
memset(elfHdrBuf, 0, sizeof(elfHdrBuf));
|
||||
read_flash_fwimage(&boot, 0, elfHdrBuf, sizeof(elfHeaderMaxBuf));
|
||||
elf_h = elfHdrBuf;
|
||||
|
||||
if (elf_open(elf_h, &is_elf32) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set up common variables based on ELF type */
|
||||
if (is_elf32) {
|
||||
elf32_header *eh = (elf32_header *)elf_h;
|
||||
elf32_program_header *ph;
|
||||
entry_count = eh->ph_entry_count;
|
||||
entry_size = eh->ph_entry_size;
|
||||
entry_off = eh->ph_offset;
|
||||
elf32_header* eh = (elf32_header*)elf_h;
|
||||
entry_count = eh->ph_entry_count;
|
||||
entry_off = eh->ph_offset;
|
||||
ph_size = sizeof(elf32_program_header);
|
||||
if (!entry_out_set) {
|
||||
*entry_out = eh->entry;
|
||||
*entry_out = eh->entry;
|
||||
entry_out_set = 1;
|
||||
}
|
||||
|
||||
wolfBoot_printf("EH entry offset: %d\n", (int)entry_off);
|
||||
ph = (elf32_program_header *)(elf_h + entry_off);
|
||||
/* Add padding until the first program header into hash function */
|
||||
len = ph[0].offset - elf_hdr_sz;
|
||||
wolfBoot_printf("Adding %d bytes padding\n", (int)len);
|
||||
while (len > 0) {
|
||||
if (len > PADDING_BLOCK_SIZE) {
|
||||
update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE);
|
||||
len -= PADDING_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, padding_block, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < entry_count; i++) {
|
||||
unsigned long paddr;
|
||||
unsigned long filesz;
|
||||
unsigned long offset;
|
||||
paddr = (unsigned long)ph[i].paddr;
|
||||
offset = (unsigned long)ph[i].offset;
|
||||
filesz = (unsigned long)ph[i].file_size;
|
||||
wolfBoot_printf("Paddr: 0x%lx offset: %lu, size: %lu\n", paddr,
|
||||
offset, filesz);
|
||||
|
||||
/* Feed any non-loaded parts to the hash function */
|
||||
if (ph[i].type != ELF_PT_LOAD) {
|
||||
len = filesz;
|
||||
//wolfBoot_printf("Feeding ghost segment, len %d\n", len);
|
||||
continue;
|
||||
while (len > 0) {
|
||||
if (len > WOLFBOOT_SHA_BLOCK_SIZE) {
|
||||
update_hash(&ctx, elf_h + offset, WOLFBOOT_SHA_BLOCK_SIZE);
|
||||
len -= WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
paddr += WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, elf_h + offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Feed the loaded parts to the hash function */
|
||||
len = filesz;
|
||||
wolfBoot_printf("Feeding stored segment, len %d\n", len);
|
||||
while (len > 0) {
|
||||
if (len > WOLFBOOT_SHA_BLOCK_SIZE) {
|
||||
update_hash(&ctx, (void *)(paddr + BASE_OFF),
|
||||
WOLFBOOT_SHA_BLOCK_SIZE);
|
||||
len -= WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
paddr += WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, (void *)(paddr + BASE_OFF),
|
||||
len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add padding until next program header, if any. */
|
||||
if ((i < entry_count - 1) && (ph[i+1].offset > (offset + filesz))) {
|
||||
unsigned long padding = ph[i+1].offset - (offset + filesz);
|
||||
wolfBoot_printf("Adding padding: %lu (from %lx to %lx)\n", padding, (unsigned long)offset + filesz, (unsigned long)ph[i+1].offset);
|
||||
while (padding > 0) {
|
||||
if (padding > PADDING_BLOCK_SIZE) {
|
||||
update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE);
|
||||
padding -= PADDING_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, padding_block, padding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final_offset = offset + filesz;
|
||||
}
|
||||
}
|
||||
} else { /* 64-bit ELF */
|
||||
elf64_header *eh = (elf64_header *)elf_h;
|
||||
elf64_program_header *ph;
|
||||
entry_count = eh->ph_entry_count;
|
||||
entry_size = eh->ph_entry_size;
|
||||
entry_off = eh->ph_offset;
|
||||
wolfBoot_printf("ELF: [CHECK] 32-bit, entry=0x%08X, "
|
||||
"ph_offset=0x%lX, ph_count=%u\n",
|
||||
eh->entry, (unsigned long)entry_off, entry_count);
|
||||
}
|
||||
else { /* 64-bit ELF */
|
||||
elf64_header* eh = (elf64_header*)elf_h;
|
||||
entry_count = eh->ph_entry_count;
|
||||
entry_off = eh->ph_offset;
|
||||
ph_size = sizeof(elf64_program_header);
|
||||
if (!entry_out_set) {
|
||||
*entry_out = eh->entry;
|
||||
*entry_out = eh->entry;
|
||||
entry_out_set = 1;
|
||||
}
|
||||
wolfBoot_printf("ELF: [CHECK] 64-bit, entry=0x%08lx, "
|
||||
"ph_offset=0x%08lx, ph_count=%d\n",
|
||||
eh->entry, (unsigned long)entry_off, entry_count);
|
||||
}
|
||||
|
||||
wolfBoot_printf("EH entry offset: %d\n", (int)entry_off);
|
||||
ph = (elf64_program_header *)(elf_h + entry_off);
|
||||
/* Add padding until the first program header into hash function */
|
||||
len = ph[0].offset - elf_hdr_sz;
|
||||
wolfBoot_printf("Adding %d bytes padding\n", len);
|
||||
while (len > 0) {
|
||||
if (len > PADDING_BLOCK_SIZE) {
|
||||
update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE);
|
||||
len -= PADDING_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, padding_block, len);
|
||||
break;
|
||||
}
|
||||
elf_hdr_sz = (size_t)elf_hdr_pht_combined_size(elf_h);
|
||||
wolfBoot_printf("ELF: [CHECK] Header size: %zu bytes\n", elf_hdr_sz);
|
||||
|
||||
/* Hash the elf header and program header in the image, assuming the PHT
|
||||
* immediately follows the ELF header */
|
||||
update_hash_flash_fwimg(&ctx, &boot, 0, elf_hdr_sz);
|
||||
|
||||
current_ph_offset = entry_off;
|
||||
|
||||
/* Calculate padding between ELF+PHT header and first segment */
|
||||
if (entry_count > 0) {
|
||||
uint64_t first_offset;
|
||||
read_flash_fwimage(&boot, current_ph_offset, ph_buf, ph_size);
|
||||
if (is_elf32) {
|
||||
first_offset = ((elf32_program_header*)ph_buf)->offset;
|
||||
}
|
||||
else {
|
||||
first_offset = ((elf64_program_header*)ph_buf)->offset;
|
||||
}
|
||||
for (i = 0; i < entry_count; i++) {
|
||||
unsigned long paddr;
|
||||
unsigned long filesz;
|
||||
unsigned long offset;
|
||||
paddr = (unsigned long)ph[i].paddr;
|
||||
offset = (unsigned long)ph[i].offset;
|
||||
filesz = (unsigned long)ph[i].file_size;
|
||||
wolfBoot_printf("Paddr: 0x%lx offset: %lu, size: %lu\n", paddr,
|
||||
offset, filesz);
|
||||
|
||||
/* Feed any non-loaded parts to the hash function */
|
||||
if (ph[i].type != ELF_PT_LOAD) {
|
||||
len = filesz;
|
||||
//wolfBoot_printf("Feeding ghost segment, len %d\n", len);
|
||||
continue;
|
||||
while (len > 0) {
|
||||
if (len > WOLFBOOT_SHA_BLOCK_SIZE) {
|
||||
update_hash(&ctx, elf_h + offset, WOLFBOOT_SHA_BLOCK_SIZE);
|
||||
len -= WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
paddr += WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, elf_h + offset, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Feed the loaded parts to the hash function */
|
||||
len = filesz;
|
||||
wolfBoot_printf("Feeding stored segment, len %d\n", len);
|
||||
while (len > 0) {
|
||||
if (len > WOLFBOOT_SHA_BLOCK_SIZE) {
|
||||
update_hash(&ctx, (void *)(paddr + BASE_OFF),
|
||||
WOLFBOOT_SHA_BLOCK_SIZE);
|
||||
len -= WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
paddr += WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, (void *)(paddr + BASE_OFF),
|
||||
len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add padding until next program header, if any. */
|
||||
if ((i < entry_count - 1) && (ph[i+1].offset > (offset + filesz))) {
|
||||
unsigned long padding = ph[i+1].offset - (offset + filesz);
|
||||
wolfBoot_printf("Adding padding: %lu\n", padding);
|
||||
while (padding > 0) {
|
||||
if (padding > PADDING_BLOCK_SIZE) {
|
||||
update_hash(&ctx, padding_block, PADDING_BLOCK_SIZE);
|
||||
padding -= PADDING_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, padding_block, padding);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final_offset = offset + filesz;
|
||||
}
|
||||
if (first_offset > elf_hdr_sz) {
|
||||
len = first_offset - elf_hdr_sz;
|
||||
wolfBoot_printf(
|
||||
"ELF: [CHECK] Adding %d bytes padding before first segment\n",
|
||||
(int32_t)len);
|
||||
update_hash_flash_fwimg(&ctx, &boot, elf_hdr_sz, len); /* Hash actual file content */
|
||||
}
|
||||
}
|
||||
if (final_offset < 0)
|
||||
return -1;
|
||||
if (final_offset + IMAGE_HEADER_SIZE > (long)boot.fw_size)
|
||||
return -1;
|
||||
|
||||
/* Walk the program header table and hash each loadable segment. */
|
||||
for (i = 0; i < entry_count; i++) {
|
||||
uint64_t paddr;
|
||||
uint64_t filesz;
|
||||
uint64_t offset;
|
||||
uint32_t type;
|
||||
uint64_t next_offset = 0; /* Initialize */
|
||||
|
||||
/* read the current program header into a local buffer */
|
||||
read_flash_fwimage(&boot, current_ph_offset, ph_buf, ph_size);
|
||||
|
||||
/* Extract common fields based on ELF type */
|
||||
if (is_elf32) {
|
||||
elf32_program_header* ph = (elf32_program_header*)ph_buf;
|
||||
paddr = ph->paddr;
|
||||
offset = ph->offset;
|
||||
filesz = ph->file_size;
|
||||
type = ph->type;
|
||||
}
|
||||
else { /* 64-bit */
|
||||
elf64_program_header* ph = (elf64_program_header*)ph_buf;
|
||||
paddr = ph->paddr;
|
||||
offset = ph->offset;
|
||||
filesz = ph->file_size;
|
||||
type = ph->type;
|
||||
}
|
||||
|
||||
/* Handle loadable segments */
|
||||
if (type == ELF_PT_LOAD) {
|
||||
uintptr_t load_addr = (uintptr_t)(paddr + BASE_OFF);
|
||||
/* Feed the loadable parts to the hash function */
|
||||
wolfBoot_printf("ELF: [CHECK] Hashing loadable segment: "
|
||||
"paddr = 0x%08lx, loadaddr = 0x%08lx, "
|
||||
"offset = 0x%08lx, size = %lu\n",
|
||||
(unsigned long)paddr, (unsigned long)load_addr,
|
||||
(unsigned long)offset, (unsigned long)filesz);
|
||||
update_hash_flash_addr(&ctx, load_addr, (uint32_t)filesz,
|
||||
PART_IS_EXT(&boot));
|
||||
}
|
||||
else {
|
||||
wolfBoot_printf("ELF: [CHECK] ERROR: non-loadable segment\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add padding until next program header, if any. */
|
||||
if (i < entry_count - 1) {
|
||||
read_flash_fwimage(&boot, current_ph_offset + ph_size, ph_next_buf,
|
||||
ph_size);
|
||||
if (is_elf32) {
|
||||
next_offset = ((elf32_program_header*)ph_next_buf)->offset;
|
||||
}
|
||||
else {
|
||||
next_offset = ((elf64_program_header*)ph_next_buf)->offset;
|
||||
}
|
||||
|
||||
if (next_offset > (offset + filesz)) {
|
||||
uint32_t padding = next_offset - (offset + filesz);
|
||||
wolfBoot_printf("ELF: [CHECK] Adding padding: %u bytes (from "
|
||||
"0x%08lx to 0x%08lx)\n",
|
||||
padding, (unsigned long)(offset + filesz),
|
||||
(unsigned long)next_offset);
|
||||
update_hash_flash_fwimg(&ctx, &boot, offset + filesz, padding); /* Hash actual file content */
|
||||
}
|
||||
}
|
||||
|
||||
final_offset =
|
||||
offset + filesz; /* Track end offset of last processed segment */
|
||||
current_ph_offset += ph_size;
|
||||
} /* End of program header loop */
|
||||
|
||||
if (final_offset < 0 && entry_count > 0) {
|
||||
/* Should have processed at least one segment if entry_count > 0 */
|
||||
wolfBoot_printf("ELF: [CHECK] Error determining final offset\n");
|
||||
return -1;
|
||||
}
|
||||
else if (final_offset < 0 && entry_count == 0) {
|
||||
/* No program headers, hash only ELF header + PHT */
|
||||
final_offset = elf_hdr_sz;
|
||||
}
|
||||
|
||||
/* Check if final offset is valid */
|
||||
if (final_offset > (int64_t)boot.fw_size) {
|
||||
wolfBoot_printf("ELF: [CHECK] Final offset (%d) exceeds image size (%d)\n",
|
||||
(int32_t)final_offset, (int32_t)boot.fw_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Hash any trailing data after the last segment/header */
|
||||
len = boot.fw_size - final_offset;
|
||||
p = boot.hdr + IMAGE_HEADER_SIZE + final_offset;
|
||||
p = get_img_hdr(&boot) + IMAGE_HEADER_SIZE + final_offset;
|
||||
|
||||
wolfBoot_printf("Appending %d bytes of data from image, from position %lu...(0x%p)\n", len, IMAGE_HEADER_SIZE + final_offset, p);
|
||||
|
||||
while (len > 0) {
|
||||
if (len > WOLFBOOT_SHA_BLOCK_SIZE) {
|
||||
update_hash(&ctx, p, WOLFBOOT_SHA_BLOCK_SIZE);
|
||||
len -= WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
p += WOLFBOOT_SHA_BLOCK_SIZE;
|
||||
} else {
|
||||
update_hash(&ctx, p, len);
|
||||
break;
|
||||
}
|
||||
if (len > 0) {
|
||||
wolfBoot_printf("ELF: [CHECK] Hashing %u bytes of trailing data from "
|
||||
"offset 0x%llX\n",
|
||||
len, (unsigned long long)final_offset);
|
||||
update_hash_flash_fwimg(&ctx, &boot, final_offset, len);
|
||||
}
|
||||
|
||||
|
||||
/* Finalize SHA calculation */
|
||||
final_hash(&ctx, calc_digest);
|
||||
if (memcmp(calc_digest, exp_digest, WOLFBOOT_SHA_DIGEST_SIZE) != 0) {
|
||||
wolfBoot_printf("SHA failed for scattered ELF!\n");
|
||||
wolfBoot_printf("Expected %02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
exp_digest[0], exp_digest[1], exp_digest[2], exp_digest[3],
|
||||
exp_digest[4], exp_digest[5], exp_digest[6], exp_digest[7]);
|
||||
wolfBoot_printf("Calculated %02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
calc_digest[0], calc_digest[1], calc_digest[2], calc_digest[3],
|
||||
calc_digest[4], calc_digest[5], calc_digest[6], calc_digest[7]);
|
||||
wolfBoot_printf("ELF: [CHECK] SHA verification FAILED\n");
|
||||
wolfBoot_printf(
|
||||
"ELF: [CHECK] Expected %02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
exp_digest[0], exp_digest[1], exp_digest[2], exp_digest[3],
|
||||
exp_digest[4], exp_digest[5], exp_digest[6], exp_digest[7]);
|
||||
wolfBoot_printf(
|
||||
"ELF: [CHECK] Calculated %02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
calc_digest[0], calc_digest[1], calc_digest[2], calc_digest[3],
|
||||
calc_digest[4], calc_digest[5], calc_digest[6], calc_digest[7]);
|
||||
return -2;
|
||||
}
|
||||
wolfBoot_printf("Scattered ELF verified.\n");
|
||||
wolfBoot_printf("ELF: [CHECK] Verification successful\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wolfBoot_load_flash_image_elf(int part, unsigned long* entry_out, int ext_flash)
|
||||
{
|
||||
const unsigned char* image;
|
||||
int is_elf32;
|
||||
uint16_t entry_count;
|
||||
size_t entry_off;
|
||||
size_t ph_size;
|
||||
int i;
|
||||
const void* eh;
|
||||
struct wolfBoot_image boot;
|
||||
uint8_t elfHdrBuf[sizeof(elfHeaderMaxBuf)];
|
||||
|
||||
if (wolfBoot_open_image(&boot, part) < 0) {
|
||||
return -1;
|
||||
}
|
||||
image = boot.fw_base;
|
||||
|
||||
/* Get the elf header from the image into a local buffer. We may overread
|
||||
* the buffer depending on architecture */
|
||||
memset(elfHdrBuf, 0, sizeof(elfHdrBuf));
|
||||
read_flash_fwimage(&boot, 0, elfHdrBuf, sizeof(elfHeaderMaxBuf));
|
||||
if (elf_open(elfHdrBuf, &is_elf32) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set up header pointers based on ELF type */
|
||||
if (is_elf32) {
|
||||
eh = (const elf32_header*)elfHdrBuf;
|
||||
entry_count = ((const elf32_header*)eh)->ph_entry_count;
|
||||
entry_off = ((const elf32_header*)eh)->ph_offset;
|
||||
*entry_out = (unsigned long)((const elf32_header*)eh)->entry;
|
||||
|
||||
wolfBoot_printf("ELF: [STORE] 32-bit, entry=0x%08lx, "
|
||||
"ph_offset=0x%08lx, ph_count=%d\n",
|
||||
(unsigned long)((const elf32_header*)eh)->entry,
|
||||
(unsigned long)entry_off, entry_count);
|
||||
}
|
||||
else {
|
||||
eh = (const elf64_header*)elfHdrBuf;
|
||||
entry_count = ((const elf64_header*)eh)->ph_entry_count;
|
||||
entry_off = ((const elf64_header*)eh)->ph_offset;
|
||||
*entry_out = (unsigned long)((const elf64_header*)eh)->entry;
|
||||
|
||||
wolfBoot_printf("ELF: [STORE] 64-bit, entry=0x%08lx, "
|
||||
"ph_offset=0x%08lx, ph_count=%d\n",
|
||||
(unsigned long)((const elf64_header*)eh)->entry,
|
||||
(unsigned long)entry_off, entry_count);
|
||||
}
|
||||
|
||||
/* Walk the program header table and store each loadable segment */
|
||||
for (i = 0; i < entry_count; ++i) {
|
||||
unsigned long paddr, filesz, offset;
|
||||
int is_loadable;
|
||||
uintptr_t load_addr;
|
||||
|
||||
/* Read the current program header into a local buffer */
|
||||
if (is_elf32) {
|
||||
elf32_program_header p32;
|
||||
read_flash_fwimage(&boot, entry_off, &p32, sizeof(p32));
|
||||
is_loadable = (p32.type == ELF_PT_LOAD);
|
||||
paddr = (unsigned long)p32.paddr;
|
||||
offset = (unsigned long)p32.offset;
|
||||
filesz = (unsigned long)p32.file_size;
|
||||
ph_size = sizeof(p32);
|
||||
}
|
||||
else {
|
||||
elf64_program_header p64;
|
||||
read_flash_fwimage(&boot, entry_off, &p64, sizeof(p64));
|
||||
is_loadable = (p64.type == ELF_PT_LOAD);
|
||||
paddr = (unsigned long)p64.paddr;
|
||||
offset = (unsigned long)p64.offset;
|
||||
filesz = (unsigned long)p64.file_size;
|
||||
ph_size = sizeof(p64);
|
||||
}
|
||||
/* Skip non-loadable segments */
|
||||
if (!is_loadable) {
|
||||
wolfBoot_printf("ELF: [STORE] ERROR: non-loadable segment\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
load_addr = (uintptr_t)(paddr + BASE_OFF);
|
||||
wolfBoot_printf("ELF: [STORE] Writing loadable segment: "
|
||||
"loadaddr=0x%08lx, offset=0x%08lx, size=%lu\n",
|
||||
load_addr, offset, filesz);
|
||||
copy_flash_buffered((uintptr_t)(image + offset), load_addr, filesz,
|
||||
ext_flash, ext_flash);
|
||||
|
||||
entry_off += ph_size;
|
||||
}
|
||||
|
||||
wolfBoot_printf("ELF: [STORE] Image loading complete\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef BASE_OFF
|
||||
|
||||
#endif
|
||||
|
@ -1636,6 +1966,16 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img)
|
|||
uint32_t key_mask = 0U;
|
||||
uint32_t image_part = 1U;
|
||||
int key_slot;
|
||||
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY) && \
|
||||
defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
|
||||
uint8_t* cert_chain;
|
||||
uint16_t cert_chain_size;
|
||||
int32_t cert_verify_result;
|
||||
int hsm_ret;
|
||||
|
||||
/* Reset certificate chain usage for this verification */
|
||||
g_leafKeyIdValid = 0;
|
||||
#endif
|
||||
|
||||
stored_signature_size = get_header(img, HDR_SIGNATURE, &stored_signature);
|
||||
pubkey_hint_size = get_header(img, HDR_PUBKEY, &pubkey_hint);
|
||||
|
@ -1648,7 +1988,14 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img)
|
|||
* TSIP encrypted key is installed at
|
||||
* RENESAS_TSIP_INSTALLEDKEY_ADDR
|
||||
*/
|
||||
extern int hal_renesas_init(void);
|
||||
int rc = hal_renesas_init();
|
||||
if (rc != 0) {
|
||||
wolfBoot_printf("hal_renesas_init failed! %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
key_slot = 0;
|
||||
|
||||
#elif defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \
|
||||
defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID)
|
||||
/* Don't care about the key slot, we are using a fixed wolfHSM keyId */
|
||||
|
@ -1690,6 +2037,47 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img)
|
|||
|
||||
CONFIRM_MASK_VALID(image_part, key_mask);
|
||||
|
||||
#if defined(WOLFBOOT_CERT_CHAIN_VERIFY) && \
|
||||
defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT)
|
||||
/* Check for certificate chain in the image header */
|
||||
cert_chain_size = get_header(img, HDR_CERT_CHAIN, &cert_chain);
|
||||
if (cert_chain_size > 0) {
|
||||
wolfBoot_printf("Found certificate chain (%d bytes)\n",
|
||||
cert_chain_size);
|
||||
|
||||
/* Verify certificate chain using wolfHSM's verification API. Use DMA if
|
||||
* available in the wolfHSM configuration */
|
||||
#if defined(WOLFHSM_CFG_DMA)
|
||||
wolfBoot_printf(
|
||||
"verifying cert chain and caching leaf pubkey (using DMA)\n");
|
||||
hsm_ret = wh_Client_CertVerifyDmaAndCacheLeafPubKey(
|
||||
&hsmClientCtx, cert_chain, cert_chain_size,
|
||||
hsmClientNvmIdCertRootCA, &g_certLeafKeyId, &cert_verify_result);
|
||||
#else
|
||||
wolfBoot_printf("verifying cert chain and caching leaf pubkey\n");
|
||||
hsm_ret = wh_Client_CertVerifyAndCacheLeafPubKey(
|
||||
&hsmClientCtx, cert_chain, cert_chain_size,
|
||||
hsmClientNvmIdCertRootCA, &g_certLeafKeyId, &cert_verify_result);
|
||||
#endif
|
||||
|
||||
/* Error or verification failure results in standard auth check failure
|
||||
* path */
|
||||
if (hsm_ret != 0 || cert_verify_result != 0) {
|
||||
wolfBoot_printf("Certificate chain verification failed: "
|
||||
"hsm_ret=%d, verify_result=%d\n",
|
||||
hsm_ret, cert_verify_result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wolfBoot_printf("Certificate chain verified, using leaf key ID: %08x\n",
|
||||
(unsigned int)g_certLeafKeyId);
|
||||
|
||||
/* Set flag to use the leaf certificate's public key for signature
|
||||
* verification later */
|
||||
g_leafKeyIdValid = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* wolfBoot_verify_signature_ecc() does not return the result directly.
|
||||
* A call to wolfBoot_image_confirm_signature_ok() is required in order to
|
||||
* confirm that the signature verification is OK.
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
|
||||
#if defined(EXT_ENCRYPTED)
|
||||
static int encrypt_initialized = 0;
|
||||
static uint8_t encrypt_iv_nonce[ENCRYPT_NONCE_SIZE];
|
||||
static uint8_t encrypt_iv_nonce[ENCRYPT_NONCE_SIZE] XALIGNED(4);
|
||||
#if defined(__WOLFBOOT)
|
||||
#include "encrypt.h"
|
||||
#elif !defined(XMEMSET)
|
||||
|
@ -1335,6 +1335,14 @@ int wolfBoot_fallback_is_possible(void)
|
|||
#ifdef EXT_ENCRYPTED
|
||||
#include "encrypt.h"
|
||||
|
||||
#if defined(WOLFBOOT_RENESAS_TSIP)
|
||||
#include "wolfssl/wolfcrypt/port/Renesas/renesas-tsip-crypt.h"
|
||||
|
||||
/* Provides wrap_enc_key_t structure generated using
|
||||
* Renesas Security Key Management Tool. See docs/Renesas.md */
|
||||
#include "enckey_data.h"
|
||||
#endif
|
||||
|
||||
#if !defined(EXT_FLASH) && !defined(MMU)
|
||||
#error option EXT_ENCRYPTED requires EXT_FLASH or MMU mode
|
||||
#endif
|
||||
|
@ -1357,20 +1365,25 @@ static uint8_t ENCRYPT_KEY[ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE];
|
|||
|
||||
static int RAMFUNCTION hal_set_key(const uint8_t *k, const uint8_t *nonce)
|
||||
{
|
||||
uintptr_t addr, addr_align, addr_off;
|
||||
int ret = 0;
|
||||
int sel_sec = 0;
|
||||
uint32_t trailer_relative_off = 4;
|
||||
|
||||
#if !defined(WOLFBOOT_SMALL_STACK) && !defined(NVM_FLASH_WRITEONCE) && !defined(WOLFBOOT_ENCRYPT_CACHE)
|
||||
uint8_t ENCRYPT_CACHE[NVM_CACHE_SIZE] XALIGNED_STACK(32);
|
||||
#endif
|
||||
|
||||
#ifdef MMU
|
||||
#ifdef WOLFBOOT_RENESAS_TSIP
|
||||
/* must be flashed to RENESAS_TSIP_INSTALLEDENCKEY_ADDR */
|
||||
(void)k;
|
||||
(void)nonce;
|
||||
return 0;
|
||||
#elif defined(MMU)
|
||||
XMEMCPY(ENCRYPT_KEY, k, ENCRYPT_KEY_SIZE);
|
||||
XMEMCPY(ENCRYPT_KEY + ENCRYPT_KEY_SIZE, nonce, ENCRYPT_NONCE_SIZE);
|
||||
return 0;
|
||||
#else
|
||||
uintptr_t addr, addr_align, addr_off;
|
||||
int ret = 0;
|
||||
int sel_sec = 0;
|
||||
uint32_t trailer_relative_off = 4;
|
||||
#if !defined(WOLFBOOT_SMALL_STACK) && !defined(NVM_FLASH_WRITEONCE) && \
|
||||
!defined(WOLFBOOT_ENCRYPT_CACHE)
|
||||
uint8_t ENCRYPT_CACHE[NVM_CACHE_SIZE] XALIGNED_STACK(32);
|
||||
#endif
|
||||
|
||||
addr = ENCRYPT_TMP_SECRET_OFFSET + WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
addr_align = addr & (~(WOLFBOOT_SECTOR_SIZE - 1));
|
||||
addr_off = addr & (WOLFBOOT_SECTOR_SIZE - 1);
|
||||
|
@ -1463,7 +1476,11 @@ int RAMFUNCTION wolfBoot_set_encrypt_key(const uint8_t *key,
|
|||
*/
|
||||
int RAMFUNCTION wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce)
|
||||
{
|
||||
#if defined(MMU)
|
||||
#ifdef WOLFBOOT_RENESAS_TSIP
|
||||
wrap_enc_key_t* enc_key =(wrap_enc_key_t*)RENESAS_TSIP_INSTALLEDENCKEY_ADDR;
|
||||
XMEMCPY(k, enc_key->encrypted_user_key, ENCRYPT_KEY_SIZE);
|
||||
XMEMCPY(nonce, enc_key->initial_vector, ENCRYPT_NONCE_SIZE);
|
||||
#elif defined(MMU)
|
||||
XMEMCPY(k, ENCRYPT_KEY, ENCRYPT_KEY_SIZE);
|
||||
XMEMCPY(nonce, ENCRYPT_KEY + ENCRYPT_KEY_SIZE, ENCRYPT_NONCE_SIZE);
|
||||
#else
|
||||
|
@ -1491,7 +1508,9 @@ int RAMFUNCTION wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce)
|
|||
*/
|
||||
int RAMFUNCTION wolfBoot_erase_encrypt_key(void)
|
||||
{
|
||||
#if defined(MMU)
|
||||
#ifdef WOLFBOOT_RENESAS_TSIP
|
||||
/* nothing to erase */
|
||||
#elif defined(MMU)
|
||||
ForceZero(ENCRYPT_KEY, ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE);
|
||||
#else
|
||||
uint8_t ff[ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE];
|
||||
|
@ -1553,6 +1572,7 @@ int RAMFUNCTION chacha_init(void)
|
|||
#elif defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256)
|
||||
|
||||
Aes aes_dec, aes_enc;
|
||||
|
||||
/**
|
||||
* @brief Initialize AES encryption.
|
||||
*
|
||||
|
@ -1564,26 +1584,37 @@ Aes aes_dec, aes_enc;
|
|||
*/
|
||||
int aes_init(void)
|
||||
{
|
||||
int devId;
|
||||
uint8_t *stored_nonce;
|
||||
uint8_t *key;
|
||||
uint8_t ff[ENCRYPT_KEY_SIZE];
|
||||
|
||||
#ifdef WOLFBOOT_RENESAS_TSIP
|
||||
int ret;
|
||||
wrap_enc_key_t* enc_key;
|
||||
devId = RENESAS_DEVID + 1;
|
||||
enc_key =(wrap_enc_key_t*)RENESAS_TSIP_INSTALLEDENCKEY_ADDR;
|
||||
key = enc_key->encrypted_user_key;
|
||||
stored_nonce = enc_key->initial_vector;
|
||||
wolfCrypt_Init(); /* required to setup the crypto callback defaults */
|
||||
#else /* non TSIP */
|
||||
devId = INVALID_DEVID;
|
||||
#if defined(MMU) || defined(UNIT_TEST)
|
||||
uint8_t *key = ENCRYPT_KEY;
|
||||
key = ENCRYPT_KEY;
|
||||
#else
|
||||
uint8_t *key = (uint8_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS +
|
||||
key = (uint8_t*)(WOLFBOOT_PARTITION_BOOT_ADDRESS +
|
||||
ENCRYPT_TMP_SECRET_OFFSET);
|
||||
#endif
|
||||
uint8_t ff[ENCRYPT_KEY_SIZE];
|
||||
uint8_t iv_buf[ENCRYPT_NONCE_SIZE];
|
||||
uint8_t* stored_nonce;
|
||||
|
||||
#ifdef NVM_FLASH_WRITEONCE
|
||||
key -= WOLFBOOT_SECTOR_SIZE * nvm_select_fresh_sector(PART_BOOT);
|
||||
#endif
|
||||
|
||||
stored_nonce = key + ENCRYPT_KEY_SIZE;
|
||||
#endif /* WOLFBOOT_RENESAS_TSIP */
|
||||
|
||||
XMEMSET(&aes_enc, 0, sizeof(aes_enc));
|
||||
XMEMSET(&aes_dec, 0, sizeof(aes_dec));
|
||||
wc_AesInit(&aes_enc, NULL, 0);
|
||||
wc_AesInit(&aes_dec, NULL, 0);
|
||||
wc_AesInit(&aes_enc, NULL, devId);
|
||||
wc_AesInit(&aes_dec, NULL, devId);
|
||||
|
||||
/* Check against 'all 0xff' or 'all zero' cases */
|
||||
XMEMSET(ff, 0xFF, ENCRYPT_KEY_SIZE);
|
||||
|
@ -1593,12 +1624,37 @@ int aes_init(void)
|
|||
if (XMEMCMP(key, ff, ENCRYPT_KEY_SIZE) == 0)
|
||||
return -1;
|
||||
|
||||
#ifdef WOLFBOOT_RENESAS_TSIP
|
||||
/* Unwrap key and get key index */
|
||||
#if ENCRYPT_KEY_SIZE == 32
|
||||
ret = R_TSIP_GenerateAes256KeyIndex(enc_key->wufpk, enc_key->initial_vector,
|
||||
enc_key->encrypted_user_key, &aes_enc.ctx.tsip_keyIdx);
|
||||
#else
|
||||
ret = R_TSIP_GenerateAes128KeyIndex(enc_key->wufpk, enc_key->initial_vector,
|
||||
enc_key->encrypted_user_key, &aes_enc.ctx.tsip_keyIdx);
|
||||
#endif
|
||||
if (ret != TSIP_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
/* set encryption key size */
|
||||
aes_enc.ctx.keySize = ENCRYPT_KEY_SIZE;
|
||||
|
||||
/* copy TSIP ctx to decryption key */
|
||||
XMEMCPY(&aes_dec.ctx, &aes_enc.ctx, sizeof(aes_enc.ctx));
|
||||
|
||||
/* register AES crypto callback */
|
||||
wc_CryptoCb_RegisterDevice(devId, wc_tsip_AesCipher, NULL);
|
||||
#endif /* WOLFBOOT_RENESAS_TSIP */
|
||||
|
||||
/* AES_ENCRYPTION is used for both directions in CTR
|
||||
* IV is set later with "wc_AesSetIV" */
|
||||
wc_AesSetKeyDirect(&aes_enc, key, ENCRYPT_KEY_SIZE, NULL, AES_ENCRYPTION);
|
||||
wc_AesSetKeyDirect(&aes_dec, key, ENCRYPT_KEY_SIZE, NULL, AES_ENCRYPTION);
|
||||
|
||||
/* Set global IV nonce used in aes_set_iv */
|
||||
XMEMCPY(encrypt_iv_nonce, stored_nonce, ENCRYPT_NONCE_SIZE);
|
||||
XMEMCPY(iv_buf, stored_nonce, ENCRYPT_NONCE_SIZE);
|
||||
/* AES_ENCRYPTION is used for both directions in CTR */
|
||||
wc_AesSetKeyDirect(&aes_enc, key, ENCRYPT_KEY_SIZE, iv_buf, AES_ENCRYPTION);
|
||||
wc_AesSetKeyDirect(&aes_dec, key, ENCRYPT_KEY_SIZE, iv_buf, AES_ENCRYPTION);
|
||||
encrypt_initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1606,10 +1662,10 @@ int aes_init(void)
|
|||
* @brief Set the AES initialization vector (IV) for CTR mode.
|
||||
*
|
||||
* This function sets the AES initialization vector (IV) for the Counter (CTR)
|
||||
* mode encryption. It takes a 12-byte nonce and a 32-bit IV counter value to
|
||||
* mode encryption. It takes a 16-byte nonce and a 32-bit IV counter value to
|
||||
* construct the 16-byte IV used for encryption.
|
||||
*
|
||||
* @param nonce Pointer to the 12-byte nonce (IV) buffer.
|
||||
* @param nonce Pointer to the 16-byte nonce (IV) buffer.
|
||||
* @param iv_ctr The IV counter value.
|
||||
*
|
||||
*/
|
||||
|
@ -1702,7 +1758,8 @@ int RAMFUNCTION ext_flash_encrypt_write(uintptr_t address, const uint8_t *data,
|
|||
int sz = len, i, step;
|
||||
uint8_t part;
|
||||
uint32_t iv_counter = 0;
|
||||
#if defined(EXT_ENCRYPTED) && !defined(WOLFBOOT_SMALL_STACK) && !defined(NVM_FLASH_WRITEONCE)
|
||||
#if defined(EXT_ENCRYPTED) && !defined(WOLFBOOT_SMALL_STACK) && \
|
||||
!defined(NVM_FLASH_WRITEONCE)
|
||||
uint8_t ENCRYPT_CACHE[NVM_CACHE_SIZE] XALIGNED_STACK(32);
|
||||
#endif
|
||||
|
||||
|
@ -1779,8 +1836,8 @@ int RAMFUNCTION ext_flash_encrypt_write(uintptr_t address, const uint8_t *data,
|
|||
*/
|
||||
int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len)
|
||||
{
|
||||
uint8_t block[ENCRYPT_BLOCK_SIZE];
|
||||
uint8_t dec_block[ENCRYPT_BLOCK_SIZE];
|
||||
uint8_t block[ENCRYPT_BLOCK_SIZE] XALIGNED_STACK(4);
|
||||
uint8_t dec_block[ENCRYPT_BLOCK_SIZE] XALIGNED_STACK(4);
|
||||
uint32_t row_address = address, row_offset, iv_counter = 0;
|
||||
int i;
|
||||
int flash_read_size;
|
||||
|
@ -1814,9 +1871,8 @@ int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len
|
|||
crypto_set_iv(encrypt_iv_nonce, iv_counter);
|
||||
break;
|
||||
case PART_SWAP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
@ -1859,7 +1915,7 @@ int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len
|
|||
unaligned_trailer_size = read_remaining;
|
||||
if (unaligned_trailer_size > 0)
|
||||
{
|
||||
uint8_t dec_block[ENCRYPT_BLOCK_SIZE];
|
||||
uint8_t dec_block[ENCRYPT_BLOCK_SIZE] XALIGNED_STACK(4);
|
||||
if (ext_flash_read(address, block, ENCRYPT_BLOCK_SIZE)
|
||||
!= ENCRYPT_BLOCK_SIZE)
|
||||
return -1;
|
||||
|
|
|
@ -392,6 +392,7 @@ void uart_vprintf(const char* fmt, va_list argp)
|
|||
uart_write("0x", 2);
|
||||
/* fall through */
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
int n = (int)va_arg(argp, int);
|
||||
uart_writenum(n, 16, zeropad, maxdigits);
|
||||
|
|
|
@ -38,11 +38,6 @@
|
|||
int WP11_Library_Init(void);
|
||||
#endif
|
||||
|
||||
/* Support for ELF scatter/gather format */
|
||||
#ifdef WOLFBOOT_ELF_SCATTERED
|
||||
#include "elf.h"
|
||||
#endif
|
||||
|
||||
#ifdef RAM_CODE
|
||||
#ifndef TARGET_rp2350
|
||||
extern unsigned int _start_text;
|
||||
|
@ -55,7 +50,7 @@ static volatile const uint32_t __attribute__((used)) wolfboot_version = WOLFBOOT
|
|||
#ifdef EXT_FLASH
|
||||
# ifndef BUFFER_DECLARED
|
||||
# define BUFFER_DECLARED
|
||||
static uint8_t buffer[FLASHBUFFER_SIZE];
|
||||
static uint8_t buffer[FLASHBUFFER_SIZE] XALIGNED(4);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
@ -158,7 +153,7 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
|
|||
|
||||
#ifdef EXT_ENCRYPTED
|
||||
wolfBoot_get_encrypt_key(key, nonce);
|
||||
if(src->part == PART_SWAP)
|
||||
if (src->part == PART_SWAP)
|
||||
iv_counter = dst_sector_offset;
|
||||
else
|
||||
iv_counter = src_sector_offset;
|
||||
|
@ -171,14 +166,14 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
|
|||
if (PART_IS_EXT(src)) {
|
||||
#ifndef BUFFER_DECLARED
|
||||
#define BUFFER_DECLARED
|
||||
static uint8_t buffer[FLASHBUFFER_SIZE];
|
||||
static uint8_t buffer[FLASHBUFFER_SIZE] XALIGNED(4);
|
||||
#endif
|
||||
wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE);
|
||||
while (pos < WOLFBOOT_SECTOR_SIZE) {
|
||||
if (src_sector_offset + pos <
|
||||
(src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
|
||||
/* bypass decryption, copy encrypted data into swap */
|
||||
if (dst->part == PART_SWAP) {
|
||||
/* bypass decryption, copy encrypted data into swap if its external */
|
||||
if (dst->part == PART_SWAP && SWAP_EXT) {
|
||||
ext_flash_read((uintptr_t)(src->hdr) + src_sector_offset + pos,
|
||||
(void *)buffer, FLASHBUFFER_SIZE);
|
||||
} else {
|
||||
|
@ -207,7 +202,7 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
|
|||
return pos;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_BACKUP
|
||||
#if !defined(DISABLE_BACKUP) && !defined(CUSTOM_PARTITION_TRAILER)
|
||||
|
||||
#ifdef EXT_ENCRYPTED
|
||||
# define TRAILER_OFFSET_WORDS \
|
||||
|
@ -219,17 +214,21 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
|
|||
/**
|
||||
* @brief Performs the final swap and erase operations during a secure update,
|
||||
* ensuring that if power is lost during the update, the process can be resumed
|
||||
* on next boot.
|
||||
* on next boot. Not supported with CUSTOM_PARTITION_TRAILER
|
||||
*
|
||||
* This function handles the final phase of the three-way swap update process.
|
||||
* It ensures that the update is atomic and power-fail safe by:
|
||||
* 1. Saving the last sector of the boot partition to the swap area
|
||||
* 1. Saving the sector at tmpBootPos (staging sector) to the swap area
|
||||
* 2. Setting a magic trailer value to mark the swap as in progress
|
||||
* 3. Erasing the last sector(s) of the boot partition
|
||||
* 4. Restoring the saved sector from swap back to boot
|
||||
* 3. Erasing the last sector(s) of the boot partition (where partition state is stored)
|
||||
* 4. Restoring the saved staging sector from swap back to boot
|
||||
* 5. Setting the boot partition state to TESTING
|
||||
* 6. Erasing the last sector(s) of the update partition
|
||||
*
|
||||
* The staging sector (tmpBootPos) is positioned right before the final sectors
|
||||
* that will be erased. This sector is preserved and used to store a magic trailer
|
||||
* that indicates a swap operation is in progress.
|
||||
*
|
||||
* The function can be called in two modes:
|
||||
* - Normal mode (resume=0): Initiates the swap and erase process
|
||||
* - Resume mode (resume=1): Checks if a swap was interrupted and completes it
|
||||
|
@ -250,6 +249,8 @@ static int wolfBoot_swap_and_final_erase(int resume)
|
|||
#endif
|
||||
);
|
||||
int swapDone = 0;
|
||||
/* Calculate position of staging sector - just before the final sectors
|
||||
* that store partition state */
|
||||
uintptr_t tmpBootPos = WOLFBOOT_PARTITION_SIZE - eraseLen -
|
||||
WOLFBOOT_SECTOR_SIZE;
|
||||
uint32_t tmpBuffer[TRAILER_OFFSET_WORDS + 1];
|
||||
|
@ -260,7 +261,8 @@ static int wolfBoot_swap_and_final_erase(int resume)
|
|||
wolfBoot_open_image(swap, PART_SWAP);
|
||||
wolfBoot_get_partition_state(PART_UPDATE, &updateState);
|
||||
|
||||
/* read trailer */
|
||||
/* Read the trailer from the staging sector to check if we're resuming an
|
||||
* interrupted operation */
|
||||
#if defined(EXT_FLASH) && PARTN_IS_EXT(PART_BOOT)
|
||||
ext_flash_read((uintptr_t)(boot->hdr + tmpBootPos), (void*)tmpBuffer,
|
||||
sizeof(tmpBuffer));
|
||||
|
@ -268,12 +270,13 @@ static int wolfBoot_swap_and_final_erase(int resume)
|
|||
memcpy(tmpBuffer, boot->hdr + tmpBootPos, sizeof(tmpBuffer));
|
||||
#endif
|
||||
|
||||
/* check for trailing magic (BOOT) */
|
||||
/* Check if the magic trailer exists - indicates an interrupted swap
|
||||
* operation */
|
||||
/* final swap and erase flag is WOLFBOOT_MAGIC_TRAIL */
|
||||
if (tmpBuffer[TRAILER_OFFSET_WORDS] == WOLFBOOT_MAGIC_TRAIL) {
|
||||
swapDone = 1;
|
||||
}
|
||||
/* if resuming, quit if swap isn't done */
|
||||
/* If we're in resume mode but no swap was in progress, return */
|
||||
if ((resume == 1) && (swapDone == 0) &&
|
||||
(updateState != IMG_STATE_FINAL_FLAGS)
|
||||
) {
|
||||
|
@ -285,35 +288,38 @@ static int wolfBoot_swap_and_final_erase(int resume)
|
|||
ext_flash_unlock();
|
||||
#endif
|
||||
|
||||
/* If update state isn't set to FINAL_FLAGS, this is the first run of the function */
|
||||
/* IMG_STATE_FINAL_FLAGS allows re-entry without blowing away swap */
|
||||
if (updateState != IMG_STATE_FINAL_FLAGS) {
|
||||
/* store the sector at tmpBootPos into swap */
|
||||
/* First, backup the staging sector (sector at tmpBootPos) into swap partition */
|
||||
/* This sector will be modified with the magic trailer, so we need to preserve it */
|
||||
wolfBoot_copy_sector(boot, swap, tmpBootPos / WOLFBOOT_SECTOR_SIZE);
|
||||
/* set FINAL_SWAP for re-entry */
|
||||
/* Mark update as being in final swap phase to allow resumption if power fails */
|
||||
wolfBoot_set_partition_state(PART_UPDATE, IMG_STATE_FINAL_FLAGS);
|
||||
}
|
||||
#ifdef EXT_ENCRYPTED
|
||||
if (swapDone == 0) {
|
||||
/* get encryption key and iv if encryption is enabled */
|
||||
/* For encrypted images: Get the encryption key and IV */
|
||||
wolfBoot_get_encrypt_key((uint8_t*)tmpBuffer,
|
||||
(uint8_t*)&tmpBuffer[ENCRYPT_KEY_SIZE/sizeof(uint32_t)]);
|
||||
/* write TRAIL, encryption key and iv if enabled to tmpBootPos*/
|
||||
/* Set the magic trailer in the buffer and write it to the staging sector */
|
||||
tmpBuffer[TRAILER_OFFSET_WORDS] = WOLFBOOT_MAGIC_TRAIL;
|
||||
|
||||
wb_flash_erase(boot, tmpBootPos, WOLFBOOT_SECTOR_SIZE);
|
||||
wb_flash_write(boot, tmpBootPos, (void*)tmpBuffer, sizeof(tmpBuffer));
|
||||
}
|
||||
#endif
|
||||
/* erase the last boot sector(s) */
|
||||
/* Erase the last sector(s) of boot partition (where partition state is stored) */
|
||||
wb_flash_erase(boot, WOLFBOOT_PARTITION_SIZE - eraseLen, eraseLen);
|
||||
/* set the encryption key */
|
||||
|
||||
#ifdef EXT_ENCRYPTED
|
||||
/* Initialize encryption with the saved key */
|
||||
wolfBoot_set_encrypt_key((uint8_t*)tmpBuffer,
|
||||
(uint8_t*)&tmpBuffer[ENCRYPT_KEY_SIZE/sizeof(uint32_t)]);
|
||||
/* wolfBoot_set_encrypt_key calls hal_flash_unlock, need to unlock again */
|
||||
hal_flash_unlock();
|
||||
#endif
|
||||
/* write the original contents of tmpBootPos back */
|
||||
/* Restore the original contents of the staging sector (with the magic trailer if encrypted) */
|
||||
if (tmpBootPos < boot->fw_size + IMAGE_HEADER_SIZE) {
|
||||
wolfBoot_copy_sector(swap, boot, tmpBootPos / WOLFBOOT_SECTOR_SIZE);
|
||||
}
|
||||
|
@ -321,10 +327,11 @@ static int wolfBoot_swap_and_final_erase(int resume)
|
|||
wb_flash_erase(boot, tmpBootPos, WOLFBOOT_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
/* mark boot as TESTING */
|
||||
/* Mark boot partition as TESTING - this tells bootloader to fallback if update fails */
|
||||
wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING);
|
||||
/* erase the last sector(s) of update. This resets the update partition state
|
||||
* to IMG_STATE_NEW */
|
||||
|
||||
/* Erase the last sector(s) of update partition */
|
||||
/* This resets the update partition state to IMG_STATE_NEW */
|
||||
wb_flash_erase(update, WOLFBOOT_PARTITION_SIZE - eraseLen, eraseLen);
|
||||
|
||||
#ifdef EXT_FLASH
|
||||
|
@ -334,7 +341,7 @@ static int wolfBoot_swap_and_final_erase(int resume)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* !DISABLE_BACKUP && !CUSTOM_PARTITION_TRAILER */
|
||||
|
||||
#ifdef DELTA_UPDATES
|
||||
|
||||
|
@ -534,9 +541,10 @@ out:
|
|||
ext_flash_lock();
|
||||
#endif
|
||||
hal_flash_lock();
|
||||
|
||||
#if !defined(DISABLE_BACKUP) && !defined(CUSTOM_PARTITION_TRAILER)
|
||||
/* start re-entrant final erase, return code is only for resumption in
|
||||
* wolfBoot_start */
|
||||
#ifndef DISABLE_BACKUP
|
||||
if (ret == 0) {
|
||||
wolfBoot_swap_and_final_erase(0);
|
||||
}
|
||||
|
@ -770,7 +778,7 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
}
|
||||
}
|
||||
|
||||
/* Erase remainder of partitions */
|
||||
/* Erase remainder of partition */
|
||||
#if defined(WOLFBOOT_FLASH_MULTI_SECTOR_ERASE) || defined(PRINTF_ENABLED)
|
||||
/* calculate number of remaining bytes */
|
||||
/* reserve 1 sector for status (2 sectors for NV write once) */
|
||||
|
@ -780,7 +788,7 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
size = WOLFBOOT_PARTITION_SIZE - (sector * sector_size) - sector_size;
|
||||
#endif
|
||||
|
||||
wolfBoot_printf("Erasing remainder of partitions (%d sectors)...\n",
|
||||
wolfBoot_printf("Erasing remainder of partition (%d sectors)...\n",
|
||||
size/sector_size);
|
||||
#endif
|
||||
|
||||
|
@ -810,36 +818,46 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
|
|||
ext_flash_lock();
|
||||
#endif
|
||||
hal_flash_lock();
|
||||
|
||||
#if !defined(CUSTOM_PARTITION_TRAILER)
|
||||
/* start re-entrant final erase, return code is only for resumption in
|
||||
* wolfBoot_start*/
|
||||
* wolfBoot_start */
|
||||
wolfBoot_swap_and_final_erase(0);
|
||||
#else
|
||||
/* Mark boot partition as TESTING - this tells bootloader to fallback if update fails */
|
||||
wolfBoot_set_partition_state(PART_BOOT, IMG_STATE_TESTING);
|
||||
#endif
|
||||
|
||||
#else /* DISABLE_BACKUP */
|
||||
#ifdef WOLFBOOT_ELF_SCATTERED
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
unsigned long entry;
|
||||
void *base = (void *)WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
void* base = (void*)WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
wolfBoot_printf("ELF Scattered image digest check\n");
|
||||
if (elf_check_image_scattered(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf("ELF Scattered image digest check: failed. Restoring scattered image...\n");
|
||||
elf_store_image_scattered(base, &entry, PART_IS_EXT(boot));
|
||||
if (elf_check_image_scattered(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf("Fatal: Could not verify digest after scattering. Panic().\n");
|
||||
if (wolfBoot_check_flash_image_elf(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf("ELF Scattered image digest check: failed. Restoring "
|
||||
"scattered image...\n");
|
||||
wolfBoot_load_flash_image_elf(PART_BOOT, &entry, PART_IS_EXT(boot));
|
||||
if (wolfBoot_check_flash_image_elf(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf(
|
||||
"Fatal: Could not verify digest after scattering. Panic().\n");
|
||||
wolfBoot_panic();
|
||||
}
|
||||
}
|
||||
wolfBoot_printf("Scattered image correctly verified. Setting entry point to %lx\n", entry);
|
||||
boot.fw_base = (void *)entry;
|
||||
wolfBoot_printf(
|
||||
"Scattered image correctly verified. Setting entry point to %lx\n",
|
||||
entry);
|
||||
boot.fw_base = (void*)entry;
|
||||
#endif
|
||||
/* Direct Swap without power fail safety */
|
||||
|
||||
hal_flash_unlock();
|
||||
#ifdef EXT_FLASH
|
||||
#ifdef EXT_FLASH
|
||||
ext_flash_unlock();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EXT_ENCRYPTED
|
||||
#ifdef EXT_ENCRYPTED
|
||||
wolfBoot_get_encrypt_key(key, nonce);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Directly copy the content of the UPDATE partition into the BOOT
|
||||
* partition. */
|
||||
|
@ -1022,7 +1040,7 @@ void RAMFUNCTION wolfBoot_start(void)
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(DISABLE_BACKUP)
|
||||
#if !defined(DISABLE_BACKUP) && !defined(CUSTOM_PARTITION_TRAILER)
|
||||
/* resume the final erase in case the power failed before it finished */
|
||||
resumedFinalErase = wolfBoot_swap_and_final_erase(1);
|
||||
if (resumedFinalErase != 0)
|
||||
|
@ -1079,20 +1097,28 @@ void RAMFUNCTION wolfBoot_start(void)
|
|||
}
|
||||
PART_SANITY_CHECK(&boot);
|
||||
|
||||
#ifdef WOLFBOOT_ELF_SCATTERED
|
||||
#ifdef WOLFBOOT_ELF_FLASH_SCATTER
|
||||
unsigned long entry;
|
||||
void *base = (void *)WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
wolfBoot_printf("ELF Scattered image digest check\n");
|
||||
if (elf_check_image_scattered(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf("ELF Scattered image digest check: failed. Restoring scattered image...\n");
|
||||
elf_store_image_scattered(base, &entry, PART_IS_EXT(boot));
|
||||
if (elf_check_image_scattered(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf("Fatal: Could not verify digest after scattering. Panic().\n");
|
||||
if (wolfBoot_check_flash_image_elf(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf("ELF Scattered image digest check: failed. Restoring "
|
||||
"scattered image...\n");
|
||||
if (wolfBoot_load_flash_image_elf(PART_BOOT, &entry,
|
||||
PART_IS_EXT(&boot)) < 0) {
|
||||
wolfBoot_printf(
|
||||
"ELF: [BOOT] ERROR: could not store scattered image\n");
|
||||
wolfBoot_panic();
|
||||
}
|
||||
if (wolfBoot_check_flash_image_elf(PART_BOOT, &entry) < 0) {
|
||||
wolfBoot_printf(
|
||||
"Fatal: Could not verify digest after scattering. Panic().\n");
|
||||
wolfBoot_panic();
|
||||
}
|
||||
}
|
||||
wolfBoot_printf("Scattered image correctly verified. Setting entry point to %lx\n", entry);
|
||||
boot.fw_base = (void *)entry;
|
||||
wolfBoot_printf(
|
||||
"Scattered image correctly verified. Setting entry point to %lx\n",
|
||||
entry);
|
||||
boot.fw_base = (void*)entry;
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -238,10 +238,10 @@ ifeq ($(TARGET),sim)
|
|||
# Override linker flags
|
||||
LDFLAGS+=-Wl,-Map=image.map
|
||||
endif
|
||||
ifeq ($(ELF_SCATTERED),1)
|
||||
ifeq ($(ELF_FLASH_SCATTER),1)
|
||||
LSCRIPT_TEMPLATE=sim_scattered.ld
|
||||
APP_OBJS=app_sim_scattered.o ../src/string.o
|
||||
CFLAGS+=-D"WOLFBOOT_ELF_SCATTERED=1" -nostartfiles -ffreestanding -static -nostdlib
|
||||
CFLAGS+=-D"WOLFBOOT_ELF_FLASH_SCATTER=1" -nostartfiles -ffreestanding -static -nostdlib
|
||||
LDFLAGS+=-ffreestanding -nostartfiles -static -T$(LSCRIPT) -nostdlib
|
||||
else
|
||||
APP_OBJS=app_sim.o
|
||||
|
@ -451,6 +451,14 @@ ifeq ($(TARGET),nxp_ls1028a)
|
|||
LSCRIPT_TEMPLATE:=AARCH64-ls1028a.ld
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET),pic32ck)
|
||||
APP_OBJS+=../hal/pic32c.o
|
||||
endif
|
||||
|
||||
ifeq ($(TARGET), pic32cz)
|
||||
APP_OBJS+=../hal/pic32c.o
|
||||
endif
|
||||
|
||||
CFLAGS+=-I../lib/wolfssl
|
||||
|
||||
ifeq ($(WOLFHSM_CLIENT),1)
|
||||
|
@ -478,10 +486,22 @@ image.srec: image.elf
|
|||
@echo "\t[SREC] $@"
|
||||
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O srec $^ $@
|
||||
|
||||
image.elf: $(APP_OBJS) $(LSCRIPT)
|
||||
ifeq ($(ELF_FLASH_SCATTER),1)
|
||||
# When ELF_FLASH_SCATTER=1, preprocess the ELF file with the squashelf tool
|
||||
SQUASHELF_TOOL = ../tools/squashelf/squashelf
|
||||
image-orig.elf: $(APP_OBJS) $(LSCRIPT)
|
||||
@echo "\t[LD] $@"
|
||||
$(Q)$(LD) $(LDFLAGS) $(APP_OBJS) $(OUTPUT_FLAG) $@
|
||||
|
||||
image.elf: image-orig.elf
|
||||
@echo "\t[SQUASHELF] $@"
|
||||
$(Q)$(SQUASHELF_TOOL) -v --nosht $< $@
|
||||
else
|
||||
# Default behavior when ELF_FLASH_SCATTER is not set
|
||||
image.elf: $(APP_OBJS) $(LSCRIPT)
|
||||
@echo "\t[LD] $@"
|
||||
$(Q)$(LD) $(LDFLAGS) $(APP_OBJS) $(OUTPUT_FLAG) $@
|
||||
endif
|
||||
|
||||
standalone: image.bin
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* app_pic32ck.c
|
||||
*
|
||||
* Test bare-metal boot-led-on application
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "target.h"
|
||||
#include "wolfboot/wolfboot.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(TARGET_pic32ck)
|
||||
|
||||
#define PORT_BASE (0x44801000U)
|
||||
|
||||
#define PORTB_BASE (PORT_BASE + 0x80 * 1)
|
||||
#define PORTB_DIRSET (*(volatile uint32_t *)(PORTB_BASE + 0x08))
|
||||
#define PORTB_DIRSET_OUT(X) (1 << (X))
|
||||
#define PORTB_OUTSET (*(volatile uint32_t *)(PORTB_BASE + 0x18))
|
||||
#define PORTB_OUTSET_OUT(X) (1 << (X))
|
||||
#define PORTB_OUTCLR (*(volatile uint32_t *)(PORTB_BASE + 0x14))
|
||||
#define PORTB_OUTCLR_OUT(X) (1 << (X))
|
||||
|
||||
#define PORTD_BASE (PORT_BASE + 0x80 * 3)
|
||||
#define PORTD_DIRSET (*(volatile uint32_t *)(PORTD_BASE + 0x08))
|
||||
#define PORTD_DIRSET_OUT(X) (1 << (X))
|
||||
#define PORTD_OUTSET (*(volatile uint32_t *)(PORTD_BASE + 0x18))
|
||||
#define PORTD_OUTSET_OUT(X) (1 << (X))
|
||||
#define PORTD_OUTCLR (*(volatile uint32_t *)(PORTD_BASE + 0x14))
|
||||
#define PORTD_OUTCLR_OUT(X) (1 << (X))
|
||||
|
||||
#define LED0_PIN (20)
|
||||
#define LED1_PIN (25)
|
||||
|
||||
static void led0_on(void)
|
||||
{
|
||||
PORTD_DIRSET = PORTD_DIRSET_OUT(LED0_PIN);
|
||||
PORTD_OUTCLR = PORTD_OUTCLR_OUT(LED0_PIN);
|
||||
}
|
||||
|
||||
static void led1_on(void)
|
||||
{
|
||||
PORTB_DIRSET = PORTB_DIRSET_OUT(LED1_PIN);
|
||||
PORTB_OUTCLR = PORTB_OUTCLR_OUT(LED1_PIN);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
uint32_t boot_version;
|
||||
hal_init();
|
||||
boot_version = wolfBoot_current_firmware_version();
|
||||
if (boot_version == 1) {
|
||||
wolfBoot_update_trigger();
|
||||
led0_on();
|
||||
} else if (boot_version >= 2) {
|
||||
wolfBoot_success();
|
||||
led1_on();
|
||||
}
|
||||
|
||||
/* Wait for reboot */
|
||||
while (1) {}
|
||||
}
|
||||
#endif /* TARGET_pic32ck */
|
|
@ -0,0 +1,72 @@
|
|||
/* app_pic32cz.c
|
||||
*
|
||||
* Test bare-metal boot-led-on application
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#include "hal.h"
|
||||
#include "target.h"
|
||||
#include "wolfboot/wolfboot.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(TARGET_pic32cz)
|
||||
|
||||
#define PORT_BASE (0x44840000U)
|
||||
|
||||
#define PORTB_BASE (PORT_BASE + 0x80 * 1)
|
||||
#define PORTB_DIRSET (*(volatile uint32_t *)(PORTB_BASE + 0x08))
|
||||
#define PORTB_DIRSET_OUT(X) (1 << (X))
|
||||
#define PORTB_OUTSET (*(volatile uint32_t *)(PORTB_BASE + 0x18))
|
||||
#define PORTB_OUTSET_OUT(X) (1 << (X))
|
||||
#define PORTB_OUTCLR (*(volatile uint32_t *)(PORTB_BASE + 0x14))
|
||||
#define PORTB_OUTCLR_OUT(X) (1 << (X))
|
||||
|
||||
#define LED0_PIN 21
|
||||
#define LED1_PIN 22
|
||||
|
||||
static void led0_on(void)
|
||||
{
|
||||
PORTB_DIRSET = PORTB_DIRSET_OUT(LED0_PIN);
|
||||
PORTB_OUTCLR = PORTB_OUTCLR_OUT(LED0_PIN);
|
||||
}
|
||||
|
||||
static void led1_on(void)
|
||||
{
|
||||
PORTB_DIRSET = PORTB_DIRSET_OUT(LED1_PIN);
|
||||
PORTB_OUTCLR = PORTB_OUTCLR_OUT(LED1_PIN);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
uint32_t boot_version;
|
||||
hal_init();
|
||||
boot_version = wolfBoot_current_firmware_version();
|
||||
if (boot_version == 1) {
|
||||
wolfBoot_update_trigger();
|
||||
led0_on();
|
||||
} else if (boot_version >= 2) {
|
||||
wolfBoot_success();
|
||||
led1_on();
|
||||
}
|
||||
|
||||
/* Wait for reboot */
|
||||
while (1) {}
|
||||
}
|
||||
#endif /* TARGET_pic32cz */
|
|
@ -168,8 +168,8 @@ const char Cfile_Banner[]=
|
|||
const char Store_hdr[] = "\n"
|
||||
"#if defined(__APPLE__) && defined(__MACH__)\n"
|
||||
"#define KEYSTORE_SECTION __attribute__((section (\"__KEYSTORE,__keystore\")))\n"
|
||||
"#elif defined(__CCRX__) /* Renesas RX */\n"
|
||||
"#define KEYSTORE_SECTION\n"
|
||||
"#elif defined(__CCRX__) || defined(WOLFBOOT_RENESAS_RSIP) || defined(WOLFBOOT_RENESAS_TSIP) || defined(WOLFBOOT_RENESAS_SCEPROTECT)\n"
|
||||
"#define KEYSTORE_SECTION /* Renesas RX */\n"
|
||||
"#elif defined(TARGET_x86_64_efi)\n"
|
||||
"#define KEYSTORE_SECTION\n"
|
||||
"#else\n"
|
||||
|
@ -258,7 +258,7 @@ const char Keystore_API[] =
|
|||
"{\n"
|
||||
" if (id >= keystore_num_pubkeys())\n"
|
||||
" return 0;\n"
|
||||
" return (int)PubKeys[id].part_id_mask;\n"
|
||||
" return PubKeys[id].part_id_mask;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"uint32_t keystore_get_key_type(int id)\n"
|
||||
|
|
|
@ -172,7 +172,7 @@ Keystore_API += "uint32_t keystore_get_mask(int id)\n"
|
|||
Keystore_API += "{\n"
|
||||
Keystore_API += " if (id >= keystore_num_pubkeys())\n"
|
||||
Keystore_API += " return -1;\n"
|
||||
Keystore_API += " return (int)PubKeys[id].part_id_mask;\n"
|
||||
Keystore_API += " return PubKeys[id].part_id_mask;\n"
|
||||
Keystore_API += "}\n\n"
|
||||
Keystore_API += "#endif /* Keystore public key size check */\n"
|
||||
Keystore_API += "#endif /* WOLFBOOT_NO_SIGN */\n"
|
||||
|
|
|
@ -158,6 +158,7 @@ static inline int fp_truncate(FILE *f, size_t len)
|
|||
#define HDR_SIGNATURE 0x20
|
||||
#define HDR_POLICY_SIGNATURE 0x21
|
||||
#define HDR_SECONDARY_SIGNATURE 0x22
|
||||
#define HDR_CERT_CHAIN 0x23
|
||||
|
||||
|
||||
#define HDR_SHA256_LEN 32
|
||||
|
@ -265,6 +266,7 @@ struct cmd_options {
|
|||
const char *policy_file;
|
||||
const char *encrypt_key_file;
|
||||
const char *delta_base_file;
|
||||
const char *cert_chain_file;
|
||||
int no_base_sha;
|
||||
char output_image_file[PATH_MAX];
|
||||
char output_diff_file[PATH_MAX];
|
||||
|
@ -356,6 +358,10 @@ static int load_key_ecc(int sign_type, uint32_t curve_sz, int curve_id,
|
|||
|
||||
*pubkey_sz = curve_sz * 2;
|
||||
*pubkey = malloc(*pubkey_sz); /* assume malloc works */
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
return -1;
|
||||
}
|
||||
initRet = ret = wc_ecc_init(&key.ecc);
|
||||
if (CMD.manual_sign || CMD.sha_only) {
|
||||
/* raw (public x + public y) */
|
||||
|
@ -425,8 +431,10 @@ static int load_key_ecc(int sign_type, uint32_t curve_sz, int curve_id,
|
|||
if (ret != 0 && initRet == 0) {
|
||||
wc_ecc_free(&key.ecc);
|
||||
}
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
free(*pubkey);
|
||||
*pubkey = NULL;
|
||||
}
|
||||
|
||||
if (ret == 0 || CMD.sign != SIGN_AUTO) {
|
||||
if (CMD.header_sz < header_sz)
|
||||
|
@ -455,9 +463,14 @@ static int load_key_rsa(int sign_type, uint32_t rsa_keysz, uint32_t rsa_pubkeysz
|
|||
uint32_t keySzOut = 0;
|
||||
|
||||
if (CMD.manual_sign || CMD.sha_only) {
|
||||
/* use public key directly */
|
||||
*pubkey = *key_buffer;
|
||||
/* Allocate and copy pubkey instead of using key_buffer directly */
|
||||
*pubkey_sz = *key_buffer_sz;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(*pubkey, *key_buffer, *pubkey_sz);
|
||||
|
||||
if (*pubkey_sz <= rsa_pubkeysz) {
|
||||
CMD.header_sz = header_sz;
|
||||
|
@ -484,8 +497,18 @@ static int load_key_rsa(int sign_type, uint32_t rsa_keysz, uint32_t rsa_pubkeysz
|
|||
}
|
||||
|
||||
if (ret > 0) {
|
||||
*pubkey = *key_buffer;
|
||||
/* Allocate and copy pubkey instead of using key_buffer directly */
|
||||
*pubkey_sz = ret;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
ret = -1;
|
||||
if (initRet == 0) {
|
||||
wc_FreeRsaKey(&key.rsa);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
memcpy(*pubkey, *key_buffer, *pubkey_sz);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
|
@ -565,6 +588,10 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
|
|||
initRet = -1;
|
||||
*pubkey_sz = ED25519_PUB_KEY_SIZE;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (CMD.manual_sign || CMD.sha_only) {
|
||||
/* raw */
|
||||
|
@ -628,6 +655,10 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
|
|||
initRet = -1;
|
||||
*pubkey_sz = ED448_PUB_KEY_SIZE;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (CMD.manual_sign || CMD.sha_only) {
|
||||
/* raw */
|
||||
|
@ -743,16 +774,26 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
|
|||
if (*key_buffer_sz == (HSS_MAX_PRIVATE_KEY_LEN +
|
||||
KEYSTORE_PUBKEY_SIZE_LMS)) {
|
||||
/* priv + pub */
|
||||
*pubkey = (*key_buffer) + HSS_MAX_PRIVATE_KEY_LEN;
|
||||
*pubkey_sz = (*key_buffer_sz) - HSS_MAX_PRIVATE_KEY_LEN;
|
||||
*pubkey_sz = KEYSTORE_PUBKEY_SIZE_LMS;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
memcpy(*pubkey, (*key_buffer) + HSS_MAX_PRIVATE_KEY_LEN, *pubkey_sz);
|
||||
ret = 0;
|
||||
printf("Found LMS key\n");
|
||||
break;
|
||||
}
|
||||
else if (*key_buffer_sz == KEYSTORE_PUBKEY_SIZE_LMS) {
|
||||
/* pub only */
|
||||
*pubkey = (*key_buffer);
|
||||
*pubkey_sz = KEYSTORE_PUBKEY_SIZE_LMS;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
memcpy(*pubkey, *key_buffer, *pubkey_sz);
|
||||
ret = 0;
|
||||
printf("Found LMS public only key\n");
|
||||
break;
|
||||
|
@ -791,16 +832,26 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
|
|||
|
||||
if (*key_buffer_sz == (priv_sz + KEYSTORE_PUBKEY_SIZE_XMSS)) {
|
||||
/* priv + pub */
|
||||
*pubkey = (*key_buffer) + priv_sz;
|
||||
*pubkey_sz = (*key_buffer_sz) - priv_sz;
|
||||
*pubkey_sz = KEYSTORE_PUBKEY_SIZE_XMSS;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
memcpy(*pubkey, (*key_buffer) + priv_sz, *pubkey_sz);
|
||||
ret = 0;
|
||||
printf("Found XMSS key\n");
|
||||
break;
|
||||
}
|
||||
else if (*key_buffer_sz == KEYSTORE_PUBKEY_SIZE_XMSS) {
|
||||
/* pub only */
|
||||
*pubkey = (*key_buffer);
|
||||
*pubkey_sz = KEYSTORE_PUBKEY_SIZE_XMSS;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
memcpy(*pubkey, *key_buffer, *pubkey_sz);
|
||||
ret = 0;
|
||||
printf("Found XMSS public only key\n");
|
||||
break;
|
||||
|
@ -844,16 +895,26 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz,
|
|||
/* priv + pub */
|
||||
ret = wc_MlDsaKey_ImportPrivRaw(&key.ml_dsa, *key_buffer,
|
||||
priv_sz);
|
||||
*pubkey = (*key_buffer) + priv_sz;
|
||||
*pubkey_sz = (*key_buffer_sz) - priv_sz;
|
||||
*pubkey_sz = pub_sz;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
memcpy(*pubkey, (*key_buffer) + priv_sz, *pubkey_sz);
|
||||
ret = 0;
|
||||
printf("Found ml-dsa key\n");
|
||||
break;
|
||||
}
|
||||
else if (*key_buffer_sz == pub_sz) {
|
||||
/* pub only */
|
||||
*pubkey = (*key_buffer);
|
||||
*pubkey_sz = pub_sz;
|
||||
*pubkey = malloc(*pubkey_sz);
|
||||
if (*pubkey == NULL) {
|
||||
printf("Pubkey malloc error!\n");
|
||||
goto failure;
|
||||
}
|
||||
memcpy(*pubkey, *key_buffer, *pubkey_sz);
|
||||
ret = 0;
|
||||
printf("Found ml-dsa public only key\n");
|
||||
break;
|
||||
|
@ -1066,6 +1127,45 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
|
|||
uint32_t digest_sz = 0;
|
||||
uint32_t image_sz = 0;
|
||||
int io_sz;
|
||||
uint8_t* cert_chain = NULL;
|
||||
uint32_t cert_chain_sz = 0;
|
||||
|
||||
/* Check certificate chain file size before allocating header, and adjust
|
||||
* header size if needed */
|
||||
if (CMD.cert_chain_file != NULL) {
|
||||
struct stat file_stat;
|
||||
|
||||
/* Get the file size */
|
||||
if (stat(CMD.cert_chain_file, &file_stat) == 0) {
|
||||
/* 2 bytes for tag + 2 bytes for length field */
|
||||
const uint32_t tag_len_size = 4;
|
||||
/* Maximum alignment padding that might be needed */
|
||||
const uint32_t max_alignment = 8;
|
||||
/* Required space = tag(2) + length(2) + data + potential alignment
|
||||
* * padding */
|
||||
const uint32_t required_space =
|
||||
tag_len_size + file_stat.st_size + max_alignment;
|
||||
|
||||
/* If the current header size is too small, increase it */
|
||||
if (CMD.header_sz < required_space) {
|
||||
/* Round up to nearest power of 2 that can hold the chain */
|
||||
const uint32_t min_header_size = 256;
|
||||
uint32_t new_size = min_header_size;
|
||||
while (new_size < required_space) {
|
||||
new_size *= 2;
|
||||
}
|
||||
|
||||
printf("Increasing header size from %u to %u bytes to fit "
|
||||
"certificate chain\n",
|
||||
CMD.header_sz, new_size);
|
||||
CMD.header_sz = new_size;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("Warning: Could not stat certificate chain file %s: %s\n",
|
||||
CMD.cert_chain_file, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
header_idx = 0;
|
||||
header = malloc(CMD.header_sz);
|
||||
|
@ -1183,6 +1283,64 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
|
|||
}
|
||||
}
|
||||
|
||||
/* Read certificate chain if provided */
|
||||
if (CMD.cert_chain_file != NULL) {
|
||||
const size_t cert_chain_tlv_hdr_sz = 4;
|
||||
struct stat file_stat;
|
||||
f = fopen(CMD.cert_chain_file, "rb");
|
||||
if (f == NULL) {
|
||||
printf("Open certificate chain file %s failed: %s\n",
|
||||
CMD.cert_chain_file, strerror(errno));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Get the file size */
|
||||
if (stat(CMD.cert_chain_file, &file_stat) != 0) {
|
||||
printf("Could not get certificate chain file size: %s\n",
|
||||
strerror(errno));
|
||||
fclose(f);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
cert_chain_sz = file_stat.st_size;
|
||||
|
||||
/* Verify that the chain will fit in our header */
|
||||
if (header_idx + cert_chain_tlv_hdr_sz + cert_chain_sz >
|
||||
CMD.header_sz) {
|
||||
printf("Error: Certificate chain too large for header (%u bytes "
|
||||
"needed, %u available)\n",
|
||||
(unsigned int)(header_idx + cert_chain_tlv_hdr_sz +
|
||||
cert_chain_sz),
|
||||
CMD.header_sz);
|
||||
fclose(f);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
cert_chain = malloc(cert_chain_sz);
|
||||
if (cert_chain == NULL) {
|
||||
printf("Certificate chain buffer malloc error!\n");
|
||||
fclose(f);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Read the entire file into the buffer */
|
||||
io_sz = (int)fread(cert_chain, 1, cert_chain_sz, f);
|
||||
fclose(f);
|
||||
|
||||
if (io_sz != (int)cert_chain_sz) {
|
||||
printf("Error reading certificate chain file: %s\n",
|
||||
strerror(errno));
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Append the certificate chain TLV - require 8-byte alignment */
|
||||
ALIGN_8(header_idx);
|
||||
header_append_tag(header, &header_idx, HDR_CERT_CHAIN, cert_chain_sz,
|
||||
cert_chain);
|
||||
|
||||
printf("Added certificate chain (%d bytes)\n", cert_chain_sz);
|
||||
}
|
||||
|
||||
/* Add padding bytes. Sha-3 val field requires 8-byte alignment */
|
||||
/* The offset '4' takes into account 2B Tag + 2B Len, so that the Value
|
||||
* starts at (addr % 8 == 0) position.
|
||||
|
@ -1693,10 +1851,16 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
|
|||
fclose(f2);
|
||||
fclose(f);
|
||||
failure:
|
||||
if (cert_chain)
|
||||
free(cert_chain);
|
||||
if (policy)
|
||||
free(policy);
|
||||
if (header)
|
||||
free(header);
|
||||
if (signature)
|
||||
free(signature);
|
||||
if (secondary_signature)
|
||||
free(secondary_signature);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2587,6 +2751,13 @@ int main(int argc, char** argv)
|
|||
CMD.custom_tlvs++;
|
||||
i += 2;
|
||||
}
|
||||
else if (strcmp(argv[i], "--cert-chain") == 0) {
|
||||
if (argc <= (i + 1)) {
|
||||
fprintf(stderr, "Missing certificate chain file argument\n");
|
||||
exit(16);
|
||||
}
|
||||
CMD.cert_chain_file = argv[++i];
|
||||
}
|
||||
else {
|
||||
i--;
|
||||
break;
|
||||
|
@ -2746,6 +2917,8 @@ int main(int argc, char** argv)
|
|||
DEBUG_PRINT("Header size: %u\n", CMD.header_sz);
|
||||
if (kbuf2)
|
||||
free(kbuf2);
|
||||
if (pubkey2)
|
||||
free(pubkey2);
|
||||
} else {
|
||||
make_header(pubkey, pubkey_sz, CMD.image_file, CMD.output_image_file);
|
||||
}
|
||||
|
@ -2758,6 +2931,9 @@ int main(int argc, char** argv)
|
|||
ret = base_diff(CMD.delta_base_file, pubkey, pubkey_sz, 16);
|
||||
}
|
||||
|
||||
/* Add pubkey cleanup */
|
||||
if (pubkey)
|
||||
free(pubkey);
|
||||
|
||||
if (kbuf)
|
||||
free(kbuf);
|
||||
|
|
|
@ -0,0 +1,267 @@
|
|||
#!/bin/bash
|
||||
# Certificate Chain Generation Script (ECC P256 or RSA)
|
||||
# Creates a certificate chain with root, intermediate, and leaf
|
||||
# Outputs DER format files plus C arrays for embedding
|
||||
# Optional: Use existing leaf private key with --leaf <file> argument
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
# Default output directory and algorithm
|
||||
OUTPUT_DIR="test-dummy-ca"
|
||||
ALGO="ecc256" # Default to ECC P-256 keys
|
||||
|
||||
# Helper functions for key operations
|
||||
generate_private_key() {
|
||||
local output_file=$1
|
||||
|
||||
if [[ "$ALGO" == "ecc256" ]]; then
|
||||
openssl ecparam -genkey -name prime256v1 -noout -out "$output_file"
|
||||
elif [[ "$ALGO" == "rsa2048" ]]; then
|
||||
openssl genrsa -out "$output_file" 2048
|
||||
elif [[ "$ALGO" == "rsa4096" ]]; then
|
||||
openssl genrsa -out "$output_file" 4096
|
||||
fi
|
||||
}
|
||||
|
||||
convert_key_to_der() {
|
||||
local input_file=$1
|
||||
local output_file=$2
|
||||
|
||||
if [[ "$ALGO" == "ecc256" ]]; then
|
||||
openssl ec -in "$input_file" -outform DER -out "$output_file"
|
||||
elif [[ "$ALGO" == "rsa2048" || "$ALGO" == "rsa4096" ]]; then
|
||||
openssl rsa -in "$input_file" -outform DER -out "$output_file"
|
||||
fi
|
||||
}
|
||||
|
||||
extract_public_key() {
|
||||
local cert_file=$1
|
||||
local pubkey_pem=$2
|
||||
local pubkey_der=$3
|
||||
|
||||
# Extract public key from certificate (same for both algos)
|
||||
openssl x509 -in "$cert_file" -pubkey -noout > "$pubkey_pem"
|
||||
|
||||
# Convert public key to DER format
|
||||
if [[ "$ALGO" == "ecc256" ]]; then
|
||||
openssl ec -pubin -in "$pubkey_pem" -outform DER -out "$pubkey_der"
|
||||
elif [[ "$ALGO" == "rsa2048" || "$ALGO" == "rsa4096" ]]; then
|
||||
openssl rsa -pubin -in "$pubkey_pem" -outform DER -out "$pubkey_der"
|
||||
fi
|
||||
}
|
||||
|
||||
validate_key_format() {
|
||||
local key_file=$1
|
||||
|
||||
if [[ "$ALGO" == "ecc256" ]]; then
|
||||
openssl ec -in "$key_file" -noout
|
||||
elif [[ "$ALGO" == "rsa2048" || "$ALGO" == "rsa4096" ]]; then
|
||||
openssl rsa -in "$key_file" -noout
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
LEAF_KEY_FILE=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--leaf)
|
||||
LEAF_KEY_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--outdir)
|
||||
OUTPUT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--algo)
|
||||
ALGO="$2"
|
||||
if [[ "$ALGO" != "ecc256" && "$ALGO" != "rsa2048" && "$ALGO" != "rsa4096" ]]; then
|
||||
echo "Invalid algorithm: $ALGO. Use 'ecc256', 'rsa2048', or 'rsa4096'"
|
||||
exit 1
|
||||
fi
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
echo "Usage: $0 [--leaf <private_key_file>] [--outdir <output_directory>] [--algo <ecc256|rsa2048|rsa4096>]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Configuration
|
||||
ROOT_SUBJECT="/C=US/ST=California/L=San Francisco/O=MyOrganization/OU=Root CA/CN=My Root CA"
|
||||
INTERMEDIATE_SUBJECT="/C=US/ST=California/L=San Francisco/O=MyOrganization/OU=Intermediate CA/CN=My Intermediate CA"
|
||||
LEAF_SUBJECT="/C=US/ST=California/L=San Francisco/O=MyOrganization/OU=Services/CN=service.example.com"
|
||||
|
||||
# Create directory structure
|
||||
echo "Creating directory structure..."
|
||||
mkdir -p ${OUTPUT_DIR}/temp
|
||||
|
||||
##################
|
||||
# GENERATE CHAIN
|
||||
##################
|
||||
echo "Generating Certificate Chain using $ALGO..."
|
||||
|
||||
# Step 1: Generate Root key and certificate
|
||||
echo "Generating Root CA..."
|
||||
generate_private_key "${OUTPUT_DIR}/temp/root.key.pem"
|
||||
|
||||
# Create PEM format root certificate (temporary)
|
||||
openssl req -new -x509 -days 3650 -sha256 \
|
||||
-key ${OUTPUT_DIR}/temp/root.key.pem \
|
||||
-out ${OUTPUT_DIR}/temp/root.crt.pem \
|
||||
-subj "$ROOT_SUBJECT" \
|
||||
-addext "basicConstraints=critical,CA:TRUE" \
|
||||
-addext "keyUsage=critical,keyCertSign,cRLSign,digitalSignature"
|
||||
|
||||
# Convert root key and certificate to DER format
|
||||
convert_key_to_der "${OUTPUT_DIR}/temp/root.key.pem" "${OUTPUT_DIR}/root-prvkey.der"
|
||||
openssl x509 -in ${OUTPUT_DIR}/temp/root.crt.pem -outform DER -out ${OUTPUT_DIR}/root-cert.der
|
||||
|
||||
# Step 2: Generate Intermediate key and CSR
|
||||
echo "Generating Intermediate CA..."
|
||||
generate_private_key "${OUTPUT_DIR}/temp/intermediate.key.pem"
|
||||
|
||||
openssl req -new -sha256 \
|
||||
-key ${OUTPUT_DIR}/temp/intermediate.key.pem \
|
||||
-out ${OUTPUT_DIR}/temp/intermediate.csr \
|
||||
-subj "$INTERMEDIATE_SUBJECT"
|
||||
|
||||
# Step 3: Sign Intermediate certificate with Root
|
||||
openssl x509 -req -days 1825 -sha256 \
|
||||
-in ${OUTPUT_DIR}/temp/intermediate.csr \
|
||||
-out ${OUTPUT_DIR}/temp/intermediate.crt.pem \
|
||||
-CA ${OUTPUT_DIR}/temp/root.crt.pem \
|
||||
-CAkey ${OUTPUT_DIR}/temp/root.key.pem \
|
||||
-CAcreateserial \
|
||||
-extfile <(printf "basicConstraints=critical,CA:TRUE,pathlen:0\nkeyUsage=critical,keyCertSign,cRLSign,digitalSignature")
|
||||
|
||||
# Convert intermediate key and certificate to DER format
|
||||
convert_key_to_der "${OUTPUT_DIR}/temp/intermediate.key.pem" "${OUTPUT_DIR}/intermediate-prvkey.der"
|
||||
openssl x509 -in ${OUTPUT_DIR}/temp/intermediate.crt.pem -outform DER -out ${OUTPUT_DIR}/intermediate-cert.der
|
||||
|
||||
# Step 4: Handle Leaf key (generate or use existing)
|
||||
echo "Handling Leaf Certificate..."
|
||||
if [ -z "$LEAF_KEY_FILE" ]; then
|
||||
echo "Generating new leaf private key..."
|
||||
generate_private_key "${OUTPUT_DIR}/temp/leaf.key.pem"
|
||||
else
|
||||
echo "Using provided leaf private key: $LEAF_KEY_FILE"
|
||||
cp "$LEAF_KEY_FILE" ${OUTPUT_DIR}/temp/leaf.key.pem
|
||||
# Ensure the key file is in the right format
|
||||
validate_key_format "${OUTPUT_DIR}/temp/leaf.key.pem"
|
||||
fi
|
||||
|
||||
# Create CSR for leaf certificate
|
||||
openssl req -new -sha256 \
|
||||
-key ${OUTPUT_DIR}/temp/leaf.key.pem \
|
||||
-out ${OUTPUT_DIR}/temp/leaf.csr \
|
||||
-subj "$LEAF_SUBJECT"
|
||||
|
||||
# Step 5: Sign Leaf certificate with Intermediate
|
||||
openssl x509 -req -days 365 -sha256 \
|
||||
-in ${OUTPUT_DIR}/temp/leaf.csr \
|
||||
-out ${OUTPUT_DIR}/temp/leaf.crt.pem \
|
||||
-CA ${OUTPUT_DIR}/temp/intermediate.crt.pem \
|
||||
-CAkey ${OUTPUT_DIR}/temp/intermediate.key.pem \
|
||||
-CAcreateserial \
|
||||
-extfile <(printf "basicConstraints=CA:FALSE\nkeyUsage=critical,digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth")
|
||||
|
||||
# Convert leaf key and certificate to DER format
|
||||
convert_key_to_der "${OUTPUT_DIR}/temp/leaf.key.pem" "${OUTPUT_DIR}/leaf-prvkey.der"
|
||||
openssl x509 -in ${OUTPUT_DIR}/temp/leaf.crt.pem -outform DER -out ${OUTPUT_DIR}/leaf-cert.der
|
||||
|
||||
# Extract the public key from leaf certificate in DER format
|
||||
echo "Extracting public key from leaf certificate..."
|
||||
extract_public_key "${OUTPUT_DIR}/temp/leaf.crt.pem" "${OUTPUT_DIR}/temp/leaf_pubkey.pem" "${OUTPUT_DIR}/leaf-pubkey.der"
|
||||
|
||||
# Create raw DER format certificate chain
|
||||
cat ${OUTPUT_DIR}/intermediate-cert.der ${OUTPUT_DIR}/leaf-cert.der > ${OUTPUT_DIR}/raw-chain.der
|
||||
|
||||
##################################
|
||||
# GENERATE C ARRAYS FOR EMBEDDING
|
||||
##################################
|
||||
echo "Generating C arrays for embedding in programs..."
|
||||
|
||||
# Create a header file for certificates
|
||||
HEADER_FILE="${OUTPUT_DIR}/gen_certificates.h"
|
||||
|
||||
# Initialize the header file with header guards and includes
|
||||
cat > "${HEADER_FILE}" << 'EOT'
|
||||
/*
|
||||
* Certificate arrays for embedded SSL/TLS applications
|
||||
* Generated by OpenSSL certificate chain script
|
||||
*/
|
||||
|
||||
#ifndef GEN_CERTIFICATES_H
|
||||
#define GEN_CERTIFICATES_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
EOT
|
||||
|
||||
# Function to append a certificate array to the header file
|
||||
append_cert_array() {
|
||||
local infile=$1
|
||||
local arrayname=$2
|
||||
local description=$3
|
||||
|
||||
echo "/* ${description} */" >> "${HEADER_FILE}"
|
||||
echo "const unsigned char ${arrayname}[] = {" >> "${HEADER_FILE}"
|
||||
|
||||
# Use xxd instead of hexdump for more reliable output
|
||||
xxd -i < "${infile}" | grep -v "unsigned char" | grep -v "unsigned int" | \
|
||||
sed 's/ 0x/0x/g' >> "${HEADER_FILE}"
|
||||
|
||||
echo "};" >> "${HEADER_FILE}"
|
||||
echo "const size_t ${arrayname}_len = sizeof(${arrayname});" >> "${HEADER_FILE}"
|
||||
echo "" >> "${HEADER_FILE}"
|
||||
}
|
||||
|
||||
### Add certificates to the header file
|
||||
echo "/* Certificates */" >> "${HEADER_FILE}"
|
||||
append_cert_array "${OUTPUT_DIR}/root-cert.der" "ROOT_CERT" "Root CA Certificate (DER format)"
|
||||
append_cert_array "${OUTPUT_DIR}/intermediate-cert.der" "INTERMEDIATE_CERT" "Intermediate CA Certificate (DER format)"
|
||||
append_cert_array "${OUTPUT_DIR}/leaf-cert.der" "LEAF_CERT" "Leaf/Server Certificate (DER format)"
|
||||
append_cert_array "${OUTPUT_DIR}/raw-chain.der" "RAW_CERT_CHAIN" "Raw Certificate Chain (Intermediate+Leaf) (DER format)"
|
||||
# Add leaf certificate public key
|
||||
append_cert_array "${OUTPUT_DIR}/leaf-pubkey.der" "LEAF_PUBKEY" "Leaf Certificate Public Key (DER format)"
|
||||
|
||||
# Close the header guard
|
||||
echo "#endif /* GEN_CERTIFICATES_H */" >> "${HEADER_FILE}"
|
||||
|
||||
echo "Generated C header file with certificate arrays: ${HEADER_FILE}"
|
||||
|
||||
# Display verification information
|
||||
echo ""
|
||||
echo "=== Certificate Chain Generation Complete ==="
|
||||
echo ""
|
||||
|
||||
# Verify Chain
|
||||
echo "=== Verifying Certificate Chain ==="
|
||||
echo "Verifying intermediate certificate against root:"
|
||||
openssl verify -CAfile ${OUTPUT_DIR}/temp/root.crt.pem ${OUTPUT_DIR}/temp/intermediate.crt.pem
|
||||
|
||||
echo ""
|
||||
echo "Verifying leaf certificate against intermediate and root:"
|
||||
openssl verify -CAfile ${OUTPUT_DIR}/temp/root.crt.pem -untrusted ${OUTPUT_DIR}/temp/intermediate.crt.pem ${OUTPUT_DIR}/temp/leaf.crt.pem
|
||||
|
||||
# Display generated files summary
|
||||
echo ""
|
||||
echo "=== Generated Files Summary ==="
|
||||
echo ""
|
||||
echo "DER Format (Algorithm: $ALGO):"
|
||||
echo " Root CA certificate: ${OUTPUT_DIR}/root-cert.der"
|
||||
echo " Root CA key: ${OUTPUT_DIR}/root-prvkey.der"
|
||||
echo " Intermediate certificate: ${OUTPUT_DIR}/intermediate-cert.der"
|
||||
echo " Intermediate key: ${OUTPUT_DIR}/intermediate-prvkey.der"
|
||||
echo " Leaf certificate: ${OUTPUT_DIR}/leaf-cert.der"
|
||||
echo " Leaf key: ${OUTPUT_DIR}/leaf-prvkey.der"
|
||||
echo " Raw chain: ${OUTPUT_DIR}/raw-chain.der"
|
||||
echo " Leaf public key: ${OUTPUT_DIR}/leaf-pubkey.der"
|
||||
echo ""
|
||||
echo "C Header file:"
|
||||
echo " Certificate arrays: ${OUTPUT_DIR}/gen_certificates.h"
|
||||
|
||||
# Clean up temporary files
|
||||
rm -rf ${OUTPUT_DIR}/temp ${OUTPUT_DIR}/root.srl ${OUTPUT_DIR}/intermediate.srl
|
|
@ -27,8 +27,14 @@ PRVKEY_DER="$WOLFBOOT_DIR/priv.der"
|
|||
PUBKEY_DER="$WOLFBOOT_DIR/priv_pub.der"
|
||||
TARGET_H="$WOLFBOOT_DIR/include/target.h"
|
||||
NVM_CONFIG="$WOLFBOOT_DIR/tools/scripts/tc3xx/wolfBoot-wolfHSM-keys.nvminit"
|
||||
NVM_CONFIG_DUMMY_CERTCHAIN="$WOLFBOOT_DIR/tools/scripts/tc3xx/wolfBoot-wolfHSM-dummy-certchain.nvminit"
|
||||
NVM_BIN="whNvmImage.bin"
|
||||
NVM_HEX="whNvmImage.hex"
|
||||
DUMMY_CERT_CHAIN="$WOLFBOOT_DIR/test-dummy-ca/raw-chain.der"
|
||||
|
||||
# Tool paths (relative to project root)
|
||||
SQUASHELF="$WOLFBOOT_DIR/tools/squashelf/squashelf"
|
||||
WHNVMTOOL="$WOLFBOOT_DIR/lib/wolfHSM/tools/whnvmtool/whnvmtool"
|
||||
|
||||
# Default algorithm configuration
|
||||
DEFAULT_SIGN_ALGO="ecc256"
|
||||
|
@ -36,8 +42,12 @@ DEFAULT_HASH_ALGO="sha256"
|
|||
|
||||
# Default values
|
||||
HSM=""
|
||||
ELF=""
|
||||
OPERATIONS=()
|
||||
|
||||
# Important Constants
|
||||
PFLASH1_RANGE="0xA0300000-0xA0500000"
|
||||
|
||||
# Structure to hold command options
|
||||
declare -A KEYGEN_OPTS=(
|
||||
[sign_algo]="$DEFAULT_SIGN_ALGO"
|
||||
|
@ -47,10 +57,12 @@ declare -A SIGN_OPTS=(
|
|||
[sign_algo]="$DEFAULT_SIGN_ALGO"
|
||||
[hash_algo]="$DEFAULT_HASH_ALGO"
|
||||
[build_type]="Release"
|
||||
[file_ext]=".bin"
|
||||
)
|
||||
declare -A MACROS_OPTS=(
|
||||
[sign_algo]=""
|
||||
[hash_algo]=""
|
||||
[use_elf_format]=""
|
||||
)
|
||||
CURRENT_OPTS=""
|
||||
|
||||
|
@ -83,53 +95,118 @@ declare -A ML_DSA_HEADER_SIZES=(
|
|||
[5]=12288
|
||||
)
|
||||
|
||||
# Get the header size based on the selected public key algorithm
|
||||
get_header_size() {
|
||||
local algo="$1"
|
||||
local pq_params="$2"
|
||||
|
||||
case "$algo" in
|
||||
"ml_dsa")
|
||||
# Default to level 2 for ML-DSA if no params specified
|
||||
echo "${ML_DSA_HEADER_SIZES[${pq_params:-2}]}"
|
||||
;;
|
||||
"ecc256") echo "256" ;;
|
||||
"ecc384"|"ecc521"|"rsa2048"|"rsa3072") echo "512" ;;
|
||||
"rsa4096") echo "1024" ;;
|
||||
"ed25519") echo "256" ;;
|
||||
"ed448") echo "512" ;;
|
||||
"lms"|"xmss") echo "0" ;; # currently not supported
|
||||
"none") echo "256" ;;
|
||||
*) echo "256" ;; # Default
|
||||
esac
|
||||
}
|
||||
|
||||
# Add to command options structure
|
||||
declare -A COMMON_OPTS=(
|
||||
[sign_pq_params]=""
|
||||
[certchain_file]=""
|
||||
[dummy_certchain]=""
|
||||
)
|
||||
|
||||
# Add LCF_OPTS to command options structure
|
||||
declare -A LCF_OPTS=(
|
||||
[sign_algo]="$DEFAULT_SIGN_ALGO"
|
||||
[use_elf_format]=""
|
||||
)
|
||||
|
||||
# Add TARGET_OPTS to command options structure
|
||||
declare -A TARGET_OPTS=(
|
||||
[use_elf_format]=""
|
||||
)
|
||||
|
||||
# Add NVM_OPTS to command options structure
|
||||
declare -A NVM_OPTS=(
|
||||
[dummy_certchain]=""
|
||||
)
|
||||
|
||||
# Get the effective certificate chain file path
|
||||
get_effective_certchain_file() {
|
||||
if [[ -n "${COMMON_OPTS[dummy_certchain]}" ]]; then
|
||||
echo "$DUMMY_CERT_CHAIN"
|
||||
elif [[ -n "${COMMON_OPTS[certchain_file]}" ]]; then
|
||||
echo "${COMMON_OPTS[certchain_file]}"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the header size based on the selected public key algorithm
|
||||
get_header_size() {
|
||||
local algo="$1"
|
||||
local pq_params="$2"
|
||||
local certchain_file="$3"
|
||||
|
||||
# Get base header size for the algorithm
|
||||
local base_size
|
||||
case "$algo" in
|
||||
"ml_dsa")
|
||||
# Default to level 2 for ML-DSA if no params specified
|
||||
base_size="${ML_DSA_HEADER_SIZES[${pq_params:-2}]}"
|
||||
;;
|
||||
"ecc256") base_size="256" ;;
|
||||
"ecc384"|"ecc521"|"rsa2048"|"rsa3072") base_size="512" ;;
|
||||
"rsa4096") base_size="1024" ;;
|
||||
"ed25519") base_size="256" ;;
|
||||
"ed448") base_size="512" ;;
|
||||
"lms"|"xmss") base_size="0" ;; # currently not supported
|
||||
"none") base_size="256" ;;
|
||||
*) base_size="256" ;; # Default
|
||||
esac
|
||||
|
||||
# If no certificate chain, return base size
|
||||
if [[ -z "$certchain_file" ]]; then
|
||||
echo "$base_size"
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if certificate chain file exists and get its size
|
||||
if [[ ! -f "$certchain_file" ]]; then
|
||||
echo "Error: Certificate chain file not found: $certchain_file" >&2
|
||||
echo "$base_size"
|
||||
return
|
||||
fi
|
||||
|
||||
local cert_size
|
||||
cert_size=$(stat -c%s "$certchain_file" 2>/dev/null || stat -f%z "$certchain_file" 2>/dev/null)
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Error: Cannot get certificate chain file size: $certchain_file" >&2
|
||||
echo "$base_size"
|
||||
return
|
||||
fi
|
||||
|
||||
# Calculate total required space
|
||||
# cert_size + 4 bytes (TLV header) + 8 bytes (max alignment padding)
|
||||
local cert_overhead=$((cert_size + 12))
|
||||
local total_required=$((base_size + cert_overhead))
|
||||
|
||||
# Round up to next power of 2 (matching C code behavior)
|
||||
local final_size=$base_size
|
||||
while [[ $final_size -lt $total_required ]]; do
|
||||
final_size=$((final_size * 2))
|
||||
done
|
||||
|
||||
echo "$final_size"
|
||||
}
|
||||
|
||||
# Helper function to display usage
|
||||
usage() {
|
||||
echo "Usage: $0 [global-options] COMMAND [command-options] [COMMAND [command-options]]"
|
||||
echo ""
|
||||
echo "Global Options:"
|
||||
echo " --hsm Use wolfHSM version"
|
||||
echo " --elf Use ELF format for firmware images (affects target, macros, lcf, and sign commands)"
|
||||
echo ""
|
||||
echo "Commands and their options:"
|
||||
echo " keygen"
|
||||
echo " --sign-algo ALGO Signing algorithm (default: ecc256)"
|
||||
echo " --localkeys Use local keys (only valid with --hsm)"
|
||||
echo " --dummy-certchain Generate dummy certificate chain after key generation"
|
||||
echo ""
|
||||
echo " sign"
|
||||
echo " --sign-algo ALGO Signing algorithm (inherits from keygen if not specified)"
|
||||
echo " --hash-algo ALGO Hash algorithm (default: sha256)"
|
||||
echo " --debug Use debug build (default: release)"
|
||||
echo " --certchain FILE Certificate chain file to include in header"
|
||||
echo " --dummy-certchain Use dummy certificate chain in header"
|
||||
echo ""
|
||||
echo " target"
|
||||
echo " No additional options"
|
||||
|
@ -140,45 +217,50 @@ usage() {
|
|||
echo " macros"
|
||||
echo " --sign-algo ALGO Signing algorithm (inherits from keygen/sign if not specified)"
|
||||
echo " --hash-algo ALGO Hash algorithm (inherits from sign if not specified)"
|
||||
echo " --certchain FILE Certificate chain file to include in header"
|
||||
echo " --dummy-certchain Use dummy certificate chain in header"
|
||||
echo ""
|
||||
echo " nvm"
|
||||
echo " No additional options"
|
||||
echo " --dummy-certchain Use dummy certificate chain configuration"
|
||||
echo ""
|
||||
echo " lcf"
|
||||
echo " --sign-algo ALGO Signing algorithm (inherits from keygen/sign if not specified)"
|
||||
echo " --certchain FILE Certificate chain file to include in header"
|
||||
echo " --dummy-certchain Use dummy certificate chain in header"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 keygen --sign-algo ecc256"
|
||||
echo " $0 sign --hash-algo sha256 --debug"
|
||||
echo " $0 keygen --sign-algo ecc256 sign --hash-algo sha256"
|
||||
echo " $0 --hsm keygen --sign-algo ecc256 --localkeys sign --debug"
|
||||
echo " $0 target"
|
||||
echo " $0 --elf target macros lcf sign"
|
||||
echo " $0 clean"
|
||||
echo " $0 macros"
|
||||
echo " $0 nvm"
|
||||
echo " $0 lcf"
|
||||
echo " $0 sign --certchain /path/to/cert_chain.pem"
|
||||
echo " $0 macros --certchain /path/to/cert_chain.pem lcf --certchain /path/to/cert_chain.pem"
|
||||
echo " $0 keygen --sign-algo ecc256 --dummy-certchain"
|
||||
echo " $0 sign --dummy-certchain"
|
||||
echo " $0 keygen --sign-algo ecc256 --dummy-certchain sign --dummy-certchain"
|
||||
echo " $0 nvm --dummy-certchain"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Function to generate keys
|
||||
do_keygen() {
|
||||
local sign_algo="${KEYGEN_OPTS[sign_algo]:-$DEFAULT_SIGN_ALGO}"
|
||||
local pq_params="${COMMON_OPTS[sign_pq_params]}"
|
||||
local header_size
|
||||
|
||||
# Get header size for current algorithm
|
||||
header_size=$(get_header_size "$sign_algo" "$pq_params")
|
||||
|
||||
echo "Generating keys with algorithm: $sign_algo"
|
||||
|
||||
# Set environment variables for keygen tool
|
||||
export IMAGE_HEADER_SIZE="$header_size"
|
||||
if [ "$sign_algo" = "ml_dsa" ]; then
|
||||
export ML_DSA_LEVEL="${pq_params:-2}" # Default to level 2 if not specified
|
||||
fi
|
||||
|
||||
(cd $WOLFBOOT_DIR && tools/keytools/keygen --"$sign_algo" -g $(basename $PRVKEY_DER) --exportpubkey \
|
||||
${KEYGEN_OPTS[nolocalkeys]:+--nolocalkeys} --der)
|
||||
|
||||
# Generate dummy certificate chain if requested
|
||||
if [[ -n "${COMMON_OPTS[dummy_certchain]}" ]]; then
|
||||
echo "Generating dummy certificate chain with algorithm: $sign_algo"
|
||||
(cd $WOLFBOOT_DIR && tools/scripts/sim-gen-dummy-chain.sh --algo "$sign_algo" --leaf priv.der)
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to sign binaries
|
||||
|
@ -188,10 +270,20 @@ do_sign() {
|
|||
local sign_algo="${SIGN_OPTS[sign_algo]:-${KEYGEN_OPTS[sign_algo]}}"
|
||||
local pq_params="${COMMON_OPTS[sign_pq_params]}"
|
||||
local header_size
|
||||
local bin_path="$base_path/$app_name/TriCore ${SIGN_OPTS[build_type]} (GCC)/$app_name.bin"
|
||||
local bin_path="$base_path/$app_name/TriCore ${SIGN_OPTS[build_type]} (GCC)/$app_name${SIGN_OPTS[file_ext]}"
|
||||
|
||||
# If signing an elf file, first preprocess it with squashelf
|
||||
if [[ "${SIGN_OPTS[file_ext]}" == ".elf" ]]; then
|
||||
local temp_file="${bin_path}.squashed"
|
||||
echo "Preprocessing ELF file with $SQUASHELF"
|
||||
"$SQUASHELF" -v --nosht -r "$PFLASH1_RANGE" "$bin_path" "$temp_file"
|
||||
echo "Replacing original ELF with squashed version"
|
||||
cp "$temp_file" "$bin_path"
|
||||
rm "$temp_file"
|
||||
fi
|
||||
|
||||
# Get header size for current algorithm
|
||||
header_size=$(get_header_size "$sign_algo" "$pq_params")
|
||||
header_size=$(get_header_size "$sign_algo" "$pq_params" "$(get_effective_certchain_file)")
|
||||
|
||||
# Set IMAGE_HEADER_SIZE environment variable for sign tool
|
||||
export IMAGE_HEADER_SIZE="$header_size"
|
||||
|
@ -199,9 +291,17 @@ do_sign() {
|
|||
echo "Signing binaries with $sign_algo and ${SIGN_OPTS[hash_algo]}"
|
||||
echo "Using header size: $header_size"
|
||||
|
||||
# Build cert-chain argument if specified
|
||||
local cert_chain_arg=""
|
||||
if [[ -n "${COMMON_OPTS[certchain_file]}" ]]; then
|
||||
cert_chain_arg="--cert-chain ${COMMON_OPTS[certchain_file]}"
|
||||
elif [[ -n "${COMMON_OPTS[dummy_certchain]}" ]]; then
|
||||
cert_chain_arg="--cert-chain $DUMMY_CERT_CHAIN"
|
||||
fi
|
||||
|
||||
# Sign for both partition 1 and 2
|
||||
../../keytools/sign --"$sign_algo" --"${SIGN_OPTS[hash_algo]}" "$bin_path" "$PRVKEY_DER" 1
|
||||
../../keytools/sign --"$sign_algo" --"${SIGN_OPTS[hash_algo]}" "$bin_path" "$PRVKEY_DER" 2
|
||||
../../keytools/sign --"$sign_algo" --"${SIGN_OPTS[hash_algo]}" $cert_chain_arg "$bin_path" "$PRVKEY_DER" 1
|
||||
../../keytools/sign --"$sign_algo" --"${SIGN_OPTS[hash_algo]}" $cert_chain_arg "$bin_path" "$PRVKEY_DER" 2
|
||||
}
|
||||
|
||||
# Function to generate target header
|
||||
|
@ -209,10 +309,28 @@ do_gen_target() {
|
|||
local target_h_template="${TARGET_H}.in"
|
||||
|
||||
local wolfboot_sector_size=0x4000
|
||||
local wolfboot_partition_size=0x17E000
|
||||
local wolfboot_partition_boot_address=0xA0300000
|
||||
local wolfboot_partition_update_address=0xA047E000
|
||||
local wolfboot_partition_swap_address=0xA05FC000
|
||||
|
||||
# Select partition values based on whether --elf option was specified
|
||||
local wolfboot_partition_size
|
||||
local wolfboot_partition_boot_address
|
||||
local wolfboot_partition_update_address
|
||||
local wolfboot_partition_swap_address
|
||||
|
||||
if [[ -n "${TARGET_OPTS[use_elf_format]}" ]]; then
|
||||
# These addresses and values must match those defined in the test-app
|
||||
# linker file
|
||||
wolfboot_partition_size=0xC0000
|
||||
wolfboot_partition_boot_address=0xA047C000
|
||||
wolfboot_partition_update_address=0xA053C000
|
||||
wolfboot_partition_swap_address=0xA05FC000
|
||||
else
|
||||
# These addresses and values must match those defined in the test-app
|
||||
# linker file
|
||||
wolfboot_partition_size=0x17C000
|
||||
wolfboot_partition_boot_address=0xA0300000
|
||||
wolfboot_partition_update_address=0xA047C000
|
||||
wolfboot_partition_swap_address=0xA05FC000
|
||||
fi
|
||||
|
||||
local wolfboot_dts_boot_address=""
|
||||
local wolfboot_dts_update_address=""
|
||||
|
@ -237,7 +355,7 @@ do_gen_target() {
|
|||
do_clean() {
|
||||
echo "Cleaning generated files"
|
||||
local macros_out="$WOLFBOOT_DIR/IDE/AURIX/wolfBoot-tc3xx${HSM:+-wolfHSM}/wolfBoot_macros.txt"
|
||||
|
||||
|
||||
rm -f "$PRVKEY_DER"
|
||||
rm -f "$PUBKEY_DER"
|
||||
rm -f "$TARGET_H"
|
||||
|
@ -258,13 +376,17 @@ do_gen_macros() {
|
|||
local pq_params="${COMMON_OPTS[sign_pq_params]}"
|
||||
|
||||
# Get header size using the new function
|
||||
local image_header_size=$(get_header_size "$sign_algo" "$pq_params")
|
||||
local image_header_size=$(get_header_size "$sign_algo" "$pq_params" "$(get_effective_certchain_file)")
|
||||
echo "generating macros with header size = $image_header_size"
|
||||
|
||||
local use_huge_stack=""
|
||||
local use_wolfhsm_pubkey_id=""
|
||||
local image_signature_size=""
|
||||
local ml_dsa_image_signature_size=""
|
||||
local ml_dsa_level=""
|
||||
local use_wolfboot_elf=""
|
||||
local use_wolfboot_elf_flash_scattered=""
|
||||
local use_wolfboot_cert_chain_verify=""
|
||||
|
||||
# Map algorithms to their macro names
|
||||
local sign_macro="${SIGN_ALGO_MAP[${sign_algo,,}]:-}"
|
||||
|
@ -279,6 +401,13 @@ do_gen_macros() {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# Validate certificate chain usage
|
||||
if [[ -n "${COMMON_OPTS[certchain_file]}" ]]; then
|
||||
use_wolfboot_cert_chain_verify="-DWOLFBOOT_CERT_CHAIN_VERIFY"
|
||||
elif [[ -n "${COMMON_OPTS[dummy_certchain]}" ]]; then
|
||||
use_wolfboot_cert_chain_verify="-DWOLFBOOT_CERT_CHAIN_VERIFY"
|
||||
fi
|
||||
|
||||
# Set huge stack for RSA4096
|
||||
if [[ "${sign_algo,,}" == "rsa4096" ]]; then
|
||||
use_huge_stack="-DWOLFBOOT_HUGE_STACK"
|
||||
|
@ -289,6 +418,12 @@ do_gen_macros() {
|
|||
use_wolfhsm_pubkey_id="-DWOLFBOOT_USE_WOLFHSM_PUBKEY_ID"
|
||||
fi
|
||||
|
||||
# Set ELF format macros if --elf option was specified
|
||||
if [[ -n "${MACROS_OPTS[use_elf_format]}" ]]; then
|
||||
use_wolfboot_elf="-DWOLFBOOT_ELF"
|
||||
use_wolfboot_elf_flash_scattered="-DWOLFBOOT_ELF_FLASH_SCATTER"
|
||||
fi
|
||||
|
||||
# Quirk: set additional (redundant) macros for ML DSA based on pq_params
|
||||
if [[ "${sign_algo,,}" == ml_dsa* ]]; then
|
||||
local level="${pq_params:-2}" # Default to level 2 if not specified
|
||||
|
@ -318,6 +453,9 @@ do_gen_macros() {
|
|||
-e "s/@ML_DSA_IMAGE_SIGNATURE_SIZE@/$ml_dsa_image_signature_size/g" \
|
||||
-e "s/@WOLFBOOT_HUGE_STACK@/$use_huge_stack/g" \
|
||||
-e "s/@WOLFBOOT_USE_WOLFHSM_PUBKEY_ID@/$use_wolfhsm_pubkey_id/g" \
|
||||
-e "s/@WOLFBOOT_ELF@/$use_wolfboot_elf/g" \
|
||||
-e "s/@WOLFBOOT_ELF_FLASH_SCATTER@/$use_wolfboot_elf_flash_scattered/g" \
|
||||
-e "s/@WOLFBOOT_CERT_CHAIN_VERIFY@/$use_wolfboot_cert_chain_verify/g" \
|
||||
"$macros_in" > "$macros_out"
|
||||
|
||||
# Remove empty lines from the output file, as they cause compiler errors
|
||||
|
@ -326,9 +464,16 @@ do_gen_macros() {
|
|||
|
||||
# Function to generate a wolfHSM NVM image
|
||||
do_gen_nvm() {
|
||||
local nvm_config_file="$NVM_CONFIG"
|
||||
|
||||
# Use dummy cert chain config if specified
|
||||
if [[ -n "${COMMON_OPTS[dummy_certchain]}" ]]; then
|
||||
nvm_config_file="$NVM_CONFIG_DUMMY_CERTCHAIN"
|
||||
fi
|
||||
|
||||
echo "Generating HSM NVM image"
|
||||
echo "Running: whnvmtool --image=$NVM_BIN --size=0x10000 --invert-erased-byte $NVM_CONFIG"
|
||||
whnvmtool --image="$NVM_BIN" --size=0x10000 --invert-erased-byte "$NVM_CONFIG"
|
||||
echo "Running: $WHNVMTOOL --image=$NVM_BIN --size=0x10000 --invert-erased-byte $nvm_config_file"
|
||||
"$WHNVMTOOL" --image="$NVM_BIN" --size=0x10000 --invert-erased-byte "$nvm_config_file"
|
||||
|
||||
echo "Converting to Intel HEX format"
|
||||
echo "Running: objcopy -I binary -O ihex --change-address 0xAFC00000 $NVM_BIN $NVM_HEX"
|
||||
|
@ -345,10 +490,19 @@ do_gen_lcf() {
|
|||
# Determine target directory based on HSM flag
|
||||
local base_dir="$WOLFBOOT_DIR/IDE/AURIX"
|
||||
local app_dir="test-app${HSM:+-wolfHSM}"
|
||||
local lcf_template="$base_dir/$app_dir/Lcf_Gnuc_Tricore_Tc.lsl.in"
|
||||
|
||||
# Select template file based on whether --elf option was specified
|
||||
local template_name
|
||||
if [[ -n "${LCF_OPTS[use_elf_format]}" ]]; then
|
||||
template_name="Lcf_Gnuc_Tricore_elf.lsl.in"
|
||||
else
|
||||
template_name="Lcf_Gnuc_Tricore_Tc.lsl.in"
|
||||
fi
|
||||
|
||||
local lcf_template="$base_dir/$app_dir/$template_name"
|
||||
local lcf_output="$base_dir/$app_dir/Lcf_Gnuc_Tricore_Tc.lsl"
|
||||
|
||||
header_size=$(get_header_size "$sign_algo" "$pq_params")
|
||||
header_size=$(get_header_size "$sign_algo" "$pq_params" "$(get_effective_certchain_file)")
|
||||
|
||||
echo "Generating LCF file with header_size=$header_size"
|
||||
sed -e "s/@LCF_WOLFBOOT_HEADER_OFFSET@/$header_size/g" \
|
||||
|
@ -363,6 +517,15 @@ while [[ $# -gt 0 ]]; do
|
|||
KEYGEN_OPTS[nolocalkeys]="1"
|
||||
shift
|
||||
;;
|
||||
--elf)
|
||||
ELF="1"
|
||||
# Set ELF mode for relevant command options
|
||||
SIGN_OPTS[file_ext]=".elf"
|
||||
LCF_OPTS[use_elf_format]="1"
|
||||
TARGET_OPTS[use_elf_format]="1"
|
||||
MACROS_OPTS[use_elf_format]="1"
|
||||
shift
|
||||
;;
|
||||
keygen|sign|target|clean|macros|nvm|lcf)
|
||||
break
|
||||
;;
|
||||
|
@ -391,7 +554,7 @@ while [[ $# -gt 0 ]]; do
|
|||
;;
|
||||
target)
|
||||
OPERATIONS+=("target")
|
||||
CURRENT_OPTS=""
|
||||
CURRENT_OPTS="TARGET_OPTS"
|
||||
shift
|
||||
;;
|
||||
clean)
|
||||
|
@ -406,7 +569,7 @@ while [[ $# -gt 0 ]]; do
|
|||
;;
|
||||
nvm)
|
||||
OPERATIONS+=("nvm")
|
||||
CURRENT_OPTS=""
|
||||
CURRENT_OPTS="NVM_OPTS"
|
||||
shift
|
||||
;;
|
||||
lcf)
|
||||
|
@ -473,6 +636,26 @@ while [[ $# -gt 0 ]]; do
|
|||
COMMON_OPTS[sign_pq_params]="$2"
|
||||
shift 2
|
||||
;;
|
||||
--certchain)
|
||||
if [[ -z "$CURRENT_OPTS" ]]; then
|
||||
echo "Error: --certchain must follow a command"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "$HSM" ]]; then
|
||||
echo "Error: --certchain can only be used with --hsm global option"
|
||||
exit 1
|
||||
fi
|
||||
COMMON_OPTS[certchain_file]="$2"
|
||||
shift 2
|
||||
;;
|
||||
--dummy-certchain)
|
||||
if [[ -z "$CURRENT_OPTS" ]]; then
|
||||
echo "Error: --dummy-certchain must follow a command"
|
||||
exit 1
|
||||
fi
|
||||
COMMON_OPTS[dummy_certchain]="1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option for ${CURRENT_OPTS:-global options}: $1"
|
||||
usage
|
||||
|
@ -486,6 +669,12 @@ if [ ${#OPERATIONS[@]} -eq 0 ]; then
|
|||
usage
|
||||
fi
|
||||
|
||||
# Validate that --certchain and --dummy-certchain are not both specified
|
||||
if [[ -n "${COMMON_OPTS[certchain_file]}" && -n "${COMMON_OPTS[dummy_certchain]}" ]]; then
|
||||
echo "Error: Cannot specify both --certchain and --dummy-certchain"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute requested operations in order
|
||||
for op in "${OPERATIONS[@]}"; do
|
||||
case $op in
|
||||
|
|
|
@ -13,7 +13,7 @@ flash.erase all
|
|||
|
||||
flash.reprogram all /erase
|
||||
data.load.binary "&testApp" 0xA0300000
|
||||
data.load.binary "&updateApp" 0xA047E000
|
||||
data.load.binary "&updateApp" 0xA047C000
|
||||
data.load.elf "&wolfBoot"
|
||||
flash.reprogram off
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
system.down
|
||||
system.up
|
||||
|
||||
|
||||
LOCAL &wolfBoot &testApp &updateApp
|
||||
&wolfBoot="..\..\..\IDE\AURIX\wolfBoot-tc3xx\TriCore Debug (GCC)\wolfBoot-tc3xx.elf"
|
||||
&testApp="..\..\..\IDE\AURIX\test-app\TriCore Debug (GCC)\test-app_v1_signed.bin"
|
||||
&updateApp="..\..\..\IDE\AURIX\test-app\TriCore Debug (GCC)\test-app_v2_signed.bin"
|
||||
|
||||
DO ~~/demo/tricore/flash/tc37x.cmm PREPAREONLY
|
||||
|
||||
flash.erase all
|
||||
|
||||
flash.reprogram all /erase
|
||||
data.load.binary "&testApp" 0xA047C000
|
||||
data.load.binary "&updateApp" 0xA053C000
|
||||
data.load.elf "&wolfBoot"
|
||||
flash.reprogram off
|
||||
|
||||
break.set core0_main
|
||||
|
||||
system.down
|
||||
system.up
|
||||
go
|
||||
|
||||
; Bring up the important views
|
||||
SYStem
|
||||
Frame /Locals /Caller
|
||||
List
|
||||
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
system.down
|
||||
system.up
|
||||
|
||||
|
||||
LOCAL &wolfBoot &testApp &updateApp
|
||||
&wolfBoot="..\..\..\IDE\AURIX\wolfBoot-tc3xx\TriCore Release (GCC)\wolfBoot-tc3xx.elf"
|
||||
&testApp="..\..\..\IDE\AURIX\test-app\TriCore Release (GCC)\test-app_v1_signed.bin"
|
||||
&updateApp="..\..\..\IDE\AURIX\test-app\TriCore Release (GCC)\test-app_v2_signed.bin"
|
||||
|
||||
DO ~~/demo/tricore/flash/tc37x.cmm PREPAREONLY
|
||||
|
||||
flash.erase all
|
||||
|
||||
flash.reprogram all /erase
|
||||
data.load.binary "&testApp" 0xA047C000
|
||||
data.load.binary "&updateApp" 0xA053C000
|
||||
data.load.elf "&wolfBoot"
|
||||
flash.reprogram off
|
||||
|
||||
break.set core0_main
|
||||
|
||||
system.down
|
||||
system.up
|
||||
go
|
||||
|
||||
; Bring up the important views
|
||||
SYStem
|
||||
Frame /Locals /Caller
|
||||
List
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ flash.erase all
|
|||
|
||||
flash.reprogram all /erase
|
||||
data.load.binary "&testApp" 0xA0300000
|
||||
data.load.binary "&updateApp" 0xA047E000
|
||||
data.load.binary "&updateApp" 0xA047C000
|
||||
data.load.elf "&wolfBoot"
|
||||
flash.reprogram off
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
# NVM config file for wolfHSM whnvmtool to create NVM image based on generated keys
|
||||
obj 1 0xFFFF 0x0000 "cert CA" ../../../test-dummy-ca/root-cert.der
|
|
@ -16,7 +16,7 @@ FLASH.Erase 0xA00A0000--0xA05FFFFF
|
|||
flash.reprogram all /erase
|
||||
|
||||
data.load.binary "&testApp" 0xA0300000
|
||||
data.load.binary "&updateApp" 0xA047E000
|
||||
data.load.binary "&updateApp" 0xA047C000
|
||||
data.load.elf "&wolfBoot"
|
||||
flash.reprogram off
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ FLASH.Erase 0xA00A0000--0xA05FFFFF
|
|||
flash.reprogram all /erase
|
||||
|
||||
data.load.binary "&testApp" 0xA0300000
|
||||
data.load.binary "&updateApp" 0xA047E000
|
||||
data.load.binary "&updateApp" 0xA047C000
|
||||
data.load.elf "&wolfBoot"
|
||||
flash.reprogram off
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# wolfBoot Squash ELF Tool
|
||||
|
||||
CC = gcc
|
||||
LD = gcc
|
||||
CFLAGS = -Wall -Wextra -Werror
|
||||
LDFLAGS =
|
||||
TARGET = squashelf
|
||||
CFLAGS_EXTRA = # Allow additional flags to be passed via command line
|
||||
|
||||
# option variables
|
||||
DEBUG_FLAGS = -g -DDEBUG
|
||||
OPTIMIZE = -O2
|
||||
|
||||
# Options
|
||||
ifeq ($(DEBUG),1)
|
||||
CFLAGS+=$(DEBUG_FLAGS)
|
||||
else
|
||||
CFLAGS+=$(OPTIMIZE)
|
||||
endif
|
||||
|
||||
.PHONY: clean all debug
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
debug: CFLAGS+=$(DEBUG_FLAGS)
|
||||
debug: all
|
||||
|
||||
$(TARGET): $(TARGET).o
|
||||
@echo "Building squashelf tool"
|
||||
$(CC) -o $@ $< $(LDFLAGS) $(CFLAGS_EXTRA)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $(CFLAGS_EXTRA) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET) *.o
|
|
@ -0,0 +1,62 @@
|
|||
# squashelf
|
||||
|
||||
`squashelf` is a command-line utility that processes ELF (Executable and Linkable Format) files. It extracts `PT_LOAD` segments, optionally filters them based on specified Load Memory Address (LMA) ranges, sorts them by LMA, and writes them to a new, reorganized ELF file. The output ELF file contains only the selected `PT_LOAD` segments and their corresponding data, potentially omitting the Section Header Table (SHT).
|
||||
|
||||
## Purpose
|
||||
|
||||
This tool can be useful for:
|
||||
|
||||
* Creating stripped-down ELF files containing only loadable code and data segments.
|
||||
* Preparing ELF files for specific bootloaders or embedded systems environments that primarily work with `PT_LOAD` segments.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
squashelf [options] <input.elf> <output.elf>
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
* `-n`, `--nosht`:
|
||||
Omit the Section Header Table (SHT) from the output ELF. By default, a minimal SHT with a single NULL section is created. Omitting the SHT shouldn't have any effect on loaders that only use PT_LOAD segments, but may cause tools like readelf to complain. Leave it in for max compatibility, or remove it for the smallest possible elf file.
|
||||
|
||||
* `-r <min>-<max>[,<min>-<max>...]`, `--range <min>-<max>[,<min>-<max>...]`:
|
||||
Specify one or more LMA ranges. Only `PT_LOAD` segments fully contained within any of these ranges (inclusive of `min`, exclusive of `max`) will be included in the output. Addresses can be provided in decimal or hexadecimal (using `0x` prefix).
|
||||
Multiple ranges can be specified by separating them with commas.
|
||||
Example: `-r 0x10000-0x20000,0x30000-0x40000` or `-r 65536-131072,196608-262144`.
|
||||
|
||||
* `-v`, `--verbose`:
|
||||
Enable verbose output, providing detailed information about the processing steps, segment selection, and file operations.
|
||||
|
||||
* `-z`, `--zero-size-segments`:
|
||||
Include segments with zero file size in the output. By default, these segments are excluded.
|
||||
|
||||
* `-h`, `--help`:
|
||||
Display a help message with detailed information about all available options and examples.
|
||||
|
||||
## Examples
|
||||
|
||||
* Extract all `PT_LOAD` segments from `input.elf`, sort them by LMA, and write them to `output_all.elf` with a minimal SHT:
|
||||
```bash
|
||||
squashelf input.elf output_all.elf
|
||||
```
|
||||
|
||||
* Extract `PT_LOAD` segments from `input.elf` that fall within the LMA range `0x80000000` to `0x8FFFFFFF`, omit the SHT, and write the result to `output_filtered.elf`:
|
||||
```bash
|
||||
squashelf --nosht --range 0x80000000-0x8FFFFFFF input.elf output_filtered.elf
|
||||
```
|
||||
|
||||
* Extract segments from multiple memory regions with verbose output:
|
||||
```bash
|
||||
squashelf -v --range 0x10000000-0x20000000,0x30000000-0x40000000 input.elf output_multi.elf
|
||||
```
|
||||
|
||||
* Include zero-size segments and show detailed processing information:
|
||||
```bash
|
||||
squashelf -v -z --range 0x10000000-0x20000000 input.elf output_with_zeros.elf
|
||||
```
|
||||
|
||||
* Display help message with all options and examples:
|
||||
```bash
|
||||
squashelf --help
|
||||
```
|
|
@ -0,0 +1,953 @@
|
|||
/* squashelf.c
|
||||
*
|
||||
* ELF file squasher
|
||||
*
|
||||
* Run on HOST machine to preprocess (squash) ELF files for the wolfBoot flash
|
||||
* updater by extracting PT_LOAD segments, optionally filtering them based on
|
||||
* specified LMA ranges, sorting them by LMA, and writing them to a new,
|
||||
* reorganized ELF file. See README.md for more information.
|
||||
*
|
||||
* Copyright (C) 2025 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfBoot.
|
||||
*
|
||||
* wolfBoot is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfBoot is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <getopt.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h> /* Needed for variadic macros */
|
||||
#include <stdbool.h> /* Needed for bool type */
|
||||
#include "../../include/elf.h"
|
||||
|
||||
/* Macro for verbose printing */
|
||||
#define DEBUG_PRINT(fmt, ...) \
|
||||
do { \
|
||||
if (verbose) \
|
||||
fprintf(stderr, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/* Constants needed from libelf/gelf.h but not in wolfBoot's elf.h */
|
||||
#define EI_NIDENT 16
|
||||
#define SHN_UNDEF 0
|
||||
|
||||
/* Structure to store an address range */
|
||||
typedef struct {
|
||||
uint64_t min;
|
||||
uint64_t max;
|
||||
} AddressRange;
|
||||
|
||||
/*
|
||||
* comparePhdr:
|
||||
* qsort comparator ordering program headers by load address (p_paddr).
|
||||
* Sorts ascending so segments land in increasing memory order.
|
||||
*/
|
||||
static int comparePhdr32(const void* a, const void* b)
|
||||
{
|
||||
const elf32_program_header* pa = a;
|
||||
const elf32_program_header* pb = b;
|
||||
if (pa->paddr < pb->paddr) {
|
||||
return -1;
|
||||
}
|
||||
if (pa->paddr > pb->paddr) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int comparePhdr64(const void* a, const void* b)
|
||||
{
|
||||
const elf64_program_header* pa = a;
|
||||
const elf64_program_header* pb = b;
|
||||
if (pa->paddr < pb->paddr) {
|
||||
return -1;
|
||||
}
|
||||
if (pa->paddr > pb->paddr) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function to parse a single range string */
|
||||
static int parseRange(const char* rangeStr, AddressRange* range)
|
||||
{
|
||||
char* copyStr = strdup(rangeStr);
|
||||
if (!copyStr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Parse the range string (e.g., "0xA00000000-0xB0000000") */
|
||||
char* dashPos = strchr(copyStr, '-');
|
||||
if (!dashPos) {
|
||||
free(copyStr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Split the string */
|
||||
*dashPos = '\0';
|
||||
char* minStr = copyStr;
|
||||
char* maxStr = dashPos + 1;
|
||||
|
||||
range->min = strtoull(minStr, NULL, 0);
|
||||
range->max = strtoull(maxStr, NULL, 0);
|
||||
|
||||
free(copyStr);
|
||||
|
||||
if (range->min >= range->max) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Function to check if an address is within any of the specified ranges */
|
||||
static bool isInRanges(uint64_t addr, AddressRange* ranges, int rangeCount)
|
||||
{
|
||||
for (int i = 0; i < rangeCount; i++) {
|
||||
if (addr >= ranges[i].min && addr <= ranges[i].max) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Function to check if two ranges overlap */
|
||||
static bool rangesOverlap(const AddressRange* a, const AddressRange* b)
|
||||
{
|
||||
return (a->min <= b->max && b->min <= a->max);
|
||||
}
|
||||
|
||||
/* Function to check if any ranges in the array overlap */
|
||||
static bool hasOverlappingRanges(AddressRange* ranges, int rangeCount)
|
||||
{
|
||||
for (int i = 0; i < rangeCount; i++) {
|
||||
for (int j = i + 1; j < rangeCount; j++) {
|
||||
if (rangesOverlap(&ranges[i], &ranges[j])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Function to parse range argument and populate ranges array */
|
||||
static bool parseRangeArgument(const char* optarg, AddressRange** ranges,
|
||||
int* rangeCount, int verbose)
|
||||
{
|
||||
/* First, count the number of ranges (commas + 1) */
|
||||
const char* ptr = optarg;
|
||||
*rangeCount = 1;
|
||||
while ((ptr = strchr(ptr, ',')) != NULL) {
|
||||
(*rangeCount)++;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
/* Allocate memory for ranges */
|
||||
*ranges = malloc(*rangeCount * sizeof(AddressRange));
|
||||
if (!*ranges) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Parse each range */
|
||||
char* rangeStr = strdup(optarg);
|
||||
if (!rangeStr) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
free(*ranges);
|
||||
*ranges = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
char* token;
|
||||
char* saveptr;
|
||||
int currRange = 0;
|
||||
|
||||
token = strtok_r(rangeStr, ",", &saveptr);
|
||||
while (token != NULL && currRange < *rangeCount) {
|
||||
if (!parseRange(token, &(*ranges)[currRange])) {
|
||||
fprintf(stderr, "Invalid range format in '%s'. Expected: min-max\n",
|
||||
token);
|
||||
free(rangeStr);
|
||||
free(*ranges);
|
||||
*ranges = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Range %d: 0x%lx - 0x%lx\n", currRange + 1,
|
||||
(*ranges)[currRange].min, (*ranges)[currRange].max);
|
||||
|
||||
currRange++;
|
||||
token = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
|
||||
free(rangeStr);
|
||||
|
||||
if (currRange != *rangeCount) {
|
||||
fprintf(stderr, "Error parsing ranges\n");
|
||||
free(*ranges);
|
||||
*ranges = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check for overlapping ranges */
|
||||
if (hasOverlappingRanges(*ranges, *rangeCount)) {
|
||||
fprintf(stderr,
|
||||
"Warning: Address ranges contain overlapping regions.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Function to print detailed help message */
|
||||
static void printHelp(const char* programName)
|
||||
{
|
||||
printf("Usage: %s [options] <input.elf> <output.elf>\n\n", programName);
|
||||
printf("Process ELF files by extracting PT_LOAD segments, optionally "
|
||||
"filtering them based on\n");
|
||||
printf("specified Load Memory Address (LMA) ranges, sorting them by LMA, "
|
||||
"and writing them to\n");
|
||||
printf("a new, reorganized ELF file.\n\n");
|
||||
|
||||
printf("Options:\n");
|
||||
printf(" -n, --nosht Omit the Section Header Table (SHT) "
|
||||
"from the output ELF.\n");
|
||||
printf(" By default, a minimal SHT with a "
|
||||
"single NULL section is created.\n");
|
||||
printf(" Omitting the SHT shouldn't have any "
|
||||
"effect on loaders that only\n");
|
||||
printf(" use PT_LOAD segments, but may cause "
|
||||
"tools like readelf to complain.\n");
|
||||
printf(" Leave it in for max compatibility, "
|
||||
"or remove it for the smallest\n");
|
||||
printf(" possible elf file.\n\n");
|
||||
|
||||
printf(" -r, --range <min>-<max>[,<min>-<max>...]\n");
|
||||
printf(" Specify one or more LMA ranges. Only "
|
||||
"PT_LOAD segments fully\n");
|
||||
printf(" contained within any of these ranges "
|
||||
"(inclusive of min, exclusive\n");
|
||||
printf(" of max) will be included in the "
|
||||
"output. Addresses can be provided\n");
|
||||
printf(" in decimal or hexadecimal (using 0x "
|
||||
"prefix).\n");
|
||||
printf(" Multiple ranges can be specified by "
|
||||
"separating them with commas.\n");
|
||||
printf(" Example: -r "
|
||||
"0x10000-0x20000,0x30000-0x40000\n\n");
|
||||
|
||||
printf(" -v, --verbose Enable verbose output, providing "
|
||||
"detailed information about\n");
|
||||
printf(" the processing steps, segment "
|
||||
"selection, and file operations.\n\n");
|
||||
|
||||
printf(" -z, --zero-size-segments Include segments with zero file size "
|
||||
"in the output.\n");
|
||||
printf(" By default, these segments are "
|
||||
"excluded.\n\n");
|
||||
|
||||
printf(
|
||||
" -h, --help Display this help message and exit.\n\n");
|
||||
|
||||
printf("Examples:\n");
|
||||
printf(" %s input.elf output.elf\n", programName);
|
||||
printf(" Extract all PT_LOAD segments, sort them by LMA, and write to "
|
||||
"output.elf\n\n");
|
||||
|
||||
printf(" %s --nosht --range 0x80000000-0x8FFFFFFF input.elf "
|
||||
"output_filtered.elf\n",
|
||||
programName);
|
||||
printf(" Extract segments within the specified range and omit the "
|
||||
"SHT\n\n");
|
||||
|
||||
printf(" %s -v --range 0x10000000-0x20000000,0x30000000-0x40000000 "
|
||||
"input.elf output_multi.elf\n",
|
||||
programName);
|
||||
printf(" Extract segments from multiple memory regions with verbose "
|
||||
"output\n\n");
|
||||
|
||||
printf(" %s -v -z --range 0x10000000-0x20000000 input.elf "
|
||||
"output_with_zeros.elf\n",
|
||||
programName);
|
||||
printf(" Include zero-size segments and show detailed processing "
|
||||
"information\n\n");
|
||||
}
|
||||
|
||||
/* Function to print usage message */
|
||||
static void printUsage(const char* programName)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: %s [-n | --nosht] [-r | --range "
|
||||
"min-max[,min-max,...]] "
|
||||
"[-v | --verbose] [-z | --zero-size-segments] "
|
||||
"[-h | --help] "
|
||||
"<input.elf> <output.elf>\n",
|
||||
programName);
|
||||
}
|
||||
|
||||
/* Read ELF header from file */
|
||||
static bool read_elf_header(int fd, void* ehdr, int* elfClass, bool* is_elf32)
|
||||
{
|
||||
uint8_t ident[EI_NIDENT];
|
||||
|
||||
/* Read ELF identification bytes */
|
||||
if (pread(fd, ident, EI_NIDENT, 0) != EI_NIDENT) {
|
||||
perror("read ELF identification");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if this is a valid ELF file */
|
||||
if (memcmp(ident, ELF_IDENT_STR, 4) != 0) {
|
||||
fprintf(stderr, "Not a valid ELF file\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Determine ELF class (32 or 64 bit) */
|
||||
*elfClass = ident[ELF_CLASS_OFF];
|
||||
if (*elfClass != ELF_CLASS_32 && *elfClass != ELF_CLASS_64) {
|
||||
fprintf(stderr, "Unsupported ELF class: %d\n", *elfClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
*is_elf32 = (*elfClass == ELF_CLASS_32);
|
||||
|
||||
/* Read the appropriate header based on class */
|
||||
if (*is_elf32) {
|
||||
elf32_header* hdr32 = (elf32_header*)ehdr;
|
||||
if (pread(fd, hdr32, sizeof(*hdr32), 0) != sizeof(*hdr32)) {
|
||||
perror("read ELF header");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elf64_header* hdr64 = (elf64_header*)ehdr;
|
||||
if (pread(fd, hdr64, sizeof(*hdr64), 0) != sizeof(*hdr64)) {
|
||||
perror("read ELF header");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Read a program header from file */
|
||||
static bool read_program_header(int fd, void* phdr, bool is_elf32, size_t index,
|
||||
off_t ph_offset, size_t ph_entsize)
|
||||
{
|
||||
off_t offset = ph_offset + (index * ph_entsize);
|
||||
|
||||
if (is_elf32) {
|
||||
elf32_program_header* ph32 = (elf32_program_header*)phdr;
|
||||
if (pread(fd, ph32, sizeof(*ph32), offset) != sizeof(*ph32)) {
|
||||
perror("read program header");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elf64_program_header* ph64 = (elf64_program_header*)phdr;
|
||||
if (pread(fd, ph64, sizeof(*ph64), offset) != sizeof(*ph64)) {
|
||||
perror("read program header");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argCount, char** argValues)
|
||||
{
|
||||
bool success = false;
|
||||
int noSht = 0;
|
||||
int hasRange = 0;
|
||||
int allowZeroSizeSeg = 0; /* New flag for zero-size segments */
|
||||
AddressRange* ranges = NULL;
|
||||
int rangeCount = 0;
|
||||
const char* inputFile = NULL;
|
||||
const char* outputFile = NULL;
|
||||
int verbose = 0;
|
||||
int opt;
|
||||
int option_index = 0; /* For getopt_long */
|
||||
int inputFd = -1;
|
||||
int outputFd = -1;
|
||||
void** data_buffers = NULL;
|
||||
size_t loadCount = 0;
|
||||
size_t phdrCount = 0;
|
||||
int elfClass = 0;
|
||||
bool is_elf32 = false;
|
||||
void* phdrs = NULL;
|
||||
void* outPhdrs = NULL;
|
||||
|
||||
/* Squash maybe uninitialized warnings introduced by -Wextra */
|
||||
phdrs = NULL;
|
||||
outPhdrs = NULL;
|
||||
|
||||
/* Allocate memory for headers */
|
||||
union {
|
||||
elf32_header h32;
|
||||
elf64_header h64;
|
||||
} elfHeader;
|
||||
|
||||
/* Define long options */
|
||||
static struct option long_options[] = {
|
||||
{"nosht", no_argument, 0, 'n'}, /* --nosht is equivalent to -n */
|
||||
{"range", required_argument, 0, 'r'}, /* --range is equivalent to -r */
|
||||
{"verbose", no_argument, 0, 'v'}, /* --verbose is equivalent to -v */
|
||||
{"zero-size-segments", no_argument, 0, 'z'}, /* --zero-size-segments */
|
||||
{"help", no_argument, 0, 'h'}, /* --help is equivalent to -h */
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
/* Use getopt_long to parse command-line options */
|
||||
optind = 1; /* Reset optind */
|
||||
while ((opt = getopt_long(argCount, argValues, "nr:vzh", long_options,
|
||||
&option_index)) != -1) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
noSht = 1;
|
||||
break;
|
||||
case 'r': {
|
||||
hasRange = 1;
|
||||
if (!parseRangeArgument(optarg, &ranges, &rangeCount,
|
||||
verbose)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'z':
|
||||
allowZeroSizeSeg = 1;
|
||||
break;
|
||||
case 'h':
|
||||
printHelp(argValues[0]);
|
||||
return EXIT_SUCCESS;
|
||||
case '?': /* getopt_long prints an error message */
|
||||
printUsage(argValues[0]);
|
||||
if (ranges) {
|
||||
free(ranges);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
default:
|
||||
/* Should not happen */
|
||||
if (ranges) {
|
||||
free(ranges);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for the correct number of positional arguments */
|
||||
if (optind + 2 != argCount) {
|
||||
printUsage(argValues[0]);
|
||||
if (ranges) {
|
||||
free(ranges);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
inputFile = argValues[optind];
|
||||
outputFile = argValues[optind + 1];
|
||||
|
||||
/* Print initial configuration if verbose */
|
||||
DEBUG_PRINT("Verbose mode enabled.\n");
|
||||
DEBUG_PRINT("Input file: %s\n", inputFile);
|
||||
DEBUG_PRINT("Output file: %s\n", outputFile);
|
||||
DEBUG_PRINT("No SHT: %s\n", noSht ? "yes" : "no");
|
||||
DEBUG_PRINT("Allow zero-size segments: %s\n",
|
||||
allowZeroSizeSeg ? "yes" : "no");
|
||||
if (hasRange) {
|
||||
DEBUG_PRINT("Range filter: %d ranges specified\n", rangeCount);
|
||||
for (int i = 0; i < rangeCount; i++) {
|
||||
DEBUG_PRINT(" Range %d: 0x%lx - 0x%lx\n", i + 1, ranges[i].min,
|
||||
ranges[i].max);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open input ELF file for reading */
|
||||
inputFd = open(inputFile, O_RDONLY);
|
||||
if (inputFd < 0) {
|
||||
perror("open inputFile");
|
||||
goto cleanup;
|
||||
}
|
||||
DEBUG_PRINT("Opened input file: %s (fd: %d)\n", inputFile, inputFd);
|
||||
|
||||
/* Read ELF header */
|
||||
if (!read_elf_header(inputFd, &elfHeader, &elfClass, &is_elf32)) {
|
||||
fprintf(stderr, "Failed to read ELF header\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Detected ELF class: %s\n", is_elf32 ? "ELF32" : "ELF64");
|
||||
|
||||
/* Get program header count */
|
||||
if (is_elf32) {
|
||||
phdrCount = elfHeader.h32.ph_entry_count;
|
||||
DEBUG_PRINT("Read input ELF header. Program header count: %u\n",
|
||||
elfHeader.h32.ph_entry_count);
|
||||
}
|
||||
else {
|
||||
phdrCount = elfHeader.h64.ph_entry_count;
|
||||
DEBUG_PRINT("Read input ELF header. Program header count: %u\n",
|
||||
elfHeader.h64.ph_entry_count);
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Confirmed program header count: %zu\n", phdrCount);
|
||||
|
||||
|
||||
|
||||
if (is_elf32) {
|
||||
phdrs = malloc(phdrCount * sizeof(elf32_program_header));
|
||||
if (!phdrs) {
|
||||
perror("malloc phdrs");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else {
|
||||
phdrs = malloc(phdrCount * sizeof(elf64_program_header));
|
||||
if (!phdrs) {
|
||||
perror("malloc phdrs");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract only PT_LOAD segments from the input PHT */
|
||||
for (size_t i = 0; i < phdrCount; i++) {
|
||||
union {
|
||||
elf32_program_header h32;
|
||||
elf64_program_header h64;
|
||||
} ph;
|
||||
|
||||
if (!read_program_header(inputFd, &ph, is_elf32, i,
|
||||
is_elf32 ? elfHeader.h32.ph_offset
|
||||
: elfHeader.h64.ph_offset,
|
||||
is_elf32 ? elfHeader.h32.ph_entry_size
|
||||
: elfHeader.h64.ph_entry_size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t p_type = is_elf32 ? ph.h32.type : ph.h64.type;
|
||||
|
||||
if (p_type == ELF_PT_LOAD) {
|
||||
uint64_t p_filesz = is_elf32 ? ph.h32.file_size : ph.h64.file_size;
|
||||
uint64_t p_paddr = is_elf32 ? ph.h32.paddr : ph.h64.paddr;
|
||||
uint64_t p_memsz = is_elf32 ? ph.h32.mem_size : ph.h64.mem_size;
|
||||
|
||||
/* Skip segments with zero filesz unless explicitly allowed */
|
||||
if (p_filesz == 0 && !allowZeroSizeSeg) {
|
||||
DEBUG_PRINT(" Skipping segment %zu (LMA 0x%lx) - "
|
||||
"zero filesz\n",
|
||||
i, (unsigned long)p_paddr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Apply range filter if specified */
|
||||
if (hasRange) {
|
||||
uint64_t segmentStart = p_paddr;
|
||||
uint64_t segmentEnd = p_paddr + p_memsz - 1;
|
||||
|
||||
/* Check if segment start and end are both within any range */
|
||||
bool startInRange =
|
||||
isInRanges(segmentStart, ranges, rangeCount);
|
||||
bool endInRange = isInRanges(segmentEnd, ranges, rangeCount);
|
||||
|
||||
if (!startInRange || !endInRange) {
|
||||
DEBUG_PRINT(" Skipping segment %zu (LMA 0x%lx - 0x%lx) - "
|
||||
"outside specified ranges\n",
|
||||
i, (unsigned long)segmentStart,
|
||||
(unsigned long)segmentEnd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the segment to the loadable segments array */
|
||||
if (is_elf32) {
|
||||
elf32_program_header* ph32_array = (elf32_program_header*)phdrs;
|
||||
memcpy(&ph32_array[loadCount], &ph.h32,
|
||||
sizeof(elf32_program_header));
|
||||
|
||||
DEBUG_PRINT(
|
||||
" Keeping segment %zu (LMA 0x%lx, size 0x%lx/0x%lx, "
|
||||
"offset 0x%lx, align %lu)\n",
|
||||
i, (unsigned long)ph.h32.paddr,
|
||||
(unsigned long)ph.h32.file_size,
|
||||
(unsigned long)ph.h32.mem_size,
|
||||
(unsigned long)ph.h32.offset, (unsigned long)ph.h32.align);
|
||||
}
|
||||
else {
|
||||
elf64_program_header* ph64_array = (elf64_program_header*)phdrs;
|
||||
memcpy(&ph64_array[loadCount], &ph.h64,
|
||||
sizeof(elf64_program_header));
|
||||
|
||||
DEBUG_PRINT(
|
||||
" Keeping segment %zu (LMA 0x%lx, size 0x%lx/0x%lx, "
|
||||
"offset 0x%lx, align %lu)\n",
|
||||
i, (unsigned long)ph.h64.paddr,
|
||||
(unsigned long)ph.h64.file_size,
|
||||
(unsigned long)ph.h64.mem_size,
|
||||
(unsigned long)ph.h64.offset, (unsigned long)ph.h64.align);
|
||||
}
|
||||
|
||||
loadCount++;
|
||||
}
|
||||
else {
|
||||
DEBUG_PRINT(" Skipping segment %zu (type %u)\n", i, p_type);
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Found %zu PT_LOAD segments matching criteria.\n", loadCount);
|
||||
if (loadCount == 0) {
|
||||
fprintf(stderr, "No PT_LOAD segments found\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Allocate memory for the output program headers */
|
||||
if (is_elf32) {
|
||||
/* Sort the loadable segments by their LMA (paddr) */
|
||||
qsort(phdrs, loadCount, sizeof(elf32_program_header), comparePhdr32);
|
||||
|
||||
outPhdrs = malloc(loadCount * sizeof(elf32_program_header));
|
||||
if (!outPhdrs) {
|
||||
perror("malloc outPhdrs");
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(outPhdrs, phdrs, loadCount * sizeof(elf32_program_header));
|
||||
}
|
||||
else {
|
||||
/* Sort the loadable segments by their LMA (paddr) */
|
||||
qsort(phdrs, loadCount, sizeof(elf64_program_header), comparePhdr64);
|
||||
|
||||
outPhdrs = malloc(loadCount * sizeof(elf64_program_header));
|
||||
if (!outPhdrs) {
|
||||
perror("malloc outPhdrs");
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(outPhdrs, phdrs, loadCount * sizeof(elf64_program_header));
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Sorted PT_LOAD segments by LMA.\n");
|
||||
|
||||
/* Allocate storage for segment data */
|
||||
data_buffers = calloc(loadCount, sizeof(void*));
|
||||
if (!data_buffers) {
|
||||
perror("calloc data_buffers");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Read segment data from input file */
|
||||
for (size_t i = 0; i < loadCount; i++) {
|
||||
uint64_t p_offset, p_filesz;
|
||||
|
||||
if (is_elf32) {
|
||||
elf32_program_header* ph32_array = (elf32_program_header*)outPhdrs;
|
||||
p_offset = ph32_array[i].offset;
|
||||
p_filesz = ph32_array[i].file_size;
|
||||
}
|
||||
else {
|
||||
elf64_program_header* ph64_array = (elf64_program_header*)outPhdrs;
|
||||
p_offset = ph64_array[i].offset;
|
||||
p_filesz = ph64_array[i].file_size;
|
||||
}
|
||||
|
||||
if (p_filesz > 0) {
|
||||
data_buffers[i] = malloc(p_filesz);
|
||||
if (!data_buffers[i]) {
|
||||
perror("malloc segment buffer");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Read the data */
|
||||
ssize_t bytes_read =
|
||||
pread(inputFd, data_buffers[i], p_filesz, p_offset);
|
||||
if (bytes_read < 0) {
|
||||
perror("pread segment data");
|
||||
goto cleanup;
|
||||
}
|
||||
else if ((size_t)bytes_read != p_filesz) {
|
||||
fprintf(stderr,
|
||||
"Short read for segment %zu (expected %lu, got %zd)\n",
|
||||
i, (unsigned long)p_filesz, bytes_read);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Read %zu bytes for segment %zu\n", (size_t)p_filesz,
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open output file for writing */
|
||||
outputFd = open(outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (outputFd < 0) {
|
||||
perror("open outputFile");
|
||||
goto cleanup;
|
||||
}
|
||||
DEBUG_PRINT("Opened output file: %s (fd: %d)\n", outputFile, outputFd);
|
||||
|
||||
/*
|
||||
* Now we manually construct the output ELF file in this format:
|
||||
* [ELF header][Program Header Table][Loadable Segments][Optional Section
|
||||
* Header Table]
|
||||
*/
|
||||
|
||||
/* Step 1: Calculate file layout */
|
||||
size_t ehdr_size = (is_elf32) ? sizeof(elf32_header) : sizeof(elf64_header);
|
||||
size_t phdr_size = (is_elf32) ? sizeof(elf32_program_header)
|
||||
: sizeof(elf64_program_header);
|
||||
|
||||
/* Calculate PHT offset and size */
|
||||
size_t pht_offset = ehdr_size;
|
||||
size_t pht_size = loadCount * phdr_size;
|
||||
|
||||
/* Calculate segment offsets and update PHDRs */
|
||||
size_t current_offset = pht_offset + pht_size;
|
||||
|
||||
/* No forced global alignment - we'll respect each segment's individual
|
||||
* alignment */
|
||||
DEBUG_PRINT("Starting segment layout at offset: 0x%lx\n", current_offset);
|
||||
|
||||
/* Update segment offsets */
|
||||
for (size_t i = 0; i < loadCount; i++) {
|
||||
uint64_t p_align, p_filesz;
|
||||
|
||||
if (is_elf32) {
|
||||
elf32_program_header* ph32_array = (elf32_program_header*)outPhdrs;
|
||||
p_align = ph32_array[i].align;
|
||||
|
||||
/* Align the segment according to its alignment requirement if
|
||||
* needed */
|
||||
if (p_align > 1) {
|
||||
current_offset =
|
||||
(current_offset + p_align - 1) & ~(p_align - 1);
|
||||
}
|
||||
|
||||
/* Update the segment's offset */
|
||||
ph32_array[i].offset = current_offset;
|
||||
p_filesz = ph32_array[i].file_size;
|
||||
|
||||
DEBUG_PRINT(" Segment %zu offset: 0x%lx\n", i,
|
||||
(unsigned long)current_offset);
|
||||
}
|
||||
else {
|
||||
elf64_program_header* ph64_array = (elf64_program_header*)outPhdrs;
|
||||
p_align = ph64_array[i].align;
|
||||
|
||||
/* Align the segment according to its alignment requirement if
|
||||
* needed */
|
||||
if (p_align > 1) {
|
||||
current_offset =
|
||||
(current_offset + p_align - 1) & ~(p_align - 1);
|
||||
}
|
||||
|
||||
/* Update the segment's offset */
|
||||
ph64_array[i].offset = current_offset;
|
||||
p_filesz = ph64_array[i].file_size;
|
||||
|
||||
DEBUG_PRINT(" Segment %zu offset: 0x%lx\n", i,
|
||||
(unsigned long)current_offset);
|
||||
}
|
||||
|
||||
/* Move to next position */
|
||||
current_offset += p_filesz;
|
||||
}
|
||||
|
||||
/* Calculate SHT offset if needed */
|
||||
size_t sht_offset = 0;
|
||||
if (!noSht) {
|
||||
/* Align SHT to 8-byte boundary */
|
||||
current_offset = (current_offset + 7) & ~7;
|
||||
sht_offset = current_offset;
|
||||
}
|
||||
|
||||
/* Step 2: Prepare and write ELF header */
|
||||
/* Update header fields */
|
||||
if (is_elf32) {
|
||||
elfHeader.h32.ph_offset = pht_offset;
|
||||
elfHeader.h32.ph_entry_count = loadCount;
|
||||
|
||||
if (noSht) {
|
||||
elfHeader.h32.sh_offset = 0;
|
||||
elfHeader.h32.sh_entry_count = 0;
|
||||
elfHeader.h32.sh_str_index = SHN_UNDEF;
|
||||
}
|
||||
else {
|
||||
elfHeader.h32.sh_offset = sht_offset;
|
||||
elfHeader.h32.sh_entry_count = 1; /* Just the NULL section */
|
||||
elfHeader.h32.sh_str_index = SHN_UNDEF;
|
||||
}
|
||||
|
||||
/* Write ELF header to output file */
|
||||
if (write(outputFd, &elfHeader.h32, sizeof(elfHeader.h32)) !=
|
||||
sizeof(elfHeader.h32)) {
|
||||
perror("write ELF header");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elfHeader.h64.ph_offset = pht_offset;
|
||||
elfHeader.h64.ph_entry_count = loadCount;
|
||||
|
||||
if (noSht) {
|
||||
elfHeader.h64.sh_offset = 0;
|
||||
elfHeader.h64.sh_entry_count = 0;
|
||||
elfHeader.h64.sh_str_index = SHN_UNDEF;
|
||||
}
|
||||
else {
|
||||
elfHeader.h64.sh_offset = sht_offset;
|
||||
elfHeader.h64.sh_entry_count = 1; /* Just the NULL section */
|
||||
elfHeader.h64.sh_str_index = SHN_UNDEF;
|
||||
}
|
||||
|
||||
/* Write ELF header to output file */
|
||||
if (write(outputFd, &elfHeader.h64, sizeof(elfHeader.h64)) !=
|
||||
sizeof(elfHeader.h64)) {
|
||||
perror("write ELF header");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Wrote ELF header to output file.\n");
|
||||
|
||||
/* Step 3: Write Program Header Table */
|
||||
if (is_elf32) {
|
||||
elf32_program_header* ph32_array = (elf32_program_header*)outPhdrs;
|
||||
|
||||
for (size_t i = 0; i < loadCount; i++) {
|
||||
if (write(outputFd, &ph32_array[i], sizeof(ph32_array[i])) !=
|
||||
sizeof(ph32_array[i])) {
|
||||
perror("write program header");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
elf64_program_header* ph64_array = (elf64_program_header*)outPhdrs;
|
||||
|
||||
for (size_t i = 0; i < loadCount; i++) {
|
||||
if (write(outputFd, &ph64_array[i], sizeof(ph64_array[i])) !=
|
||||
sizeof(ph64_array[i])) {
|
||||
perror("write program header");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Wrote Program Header Table (%zu entries).\n", loadCount);
|
||||
|
||||
/* Step 4: Write segment data */
|
||||
for (size_t i = 0; i < loadCount; i++) {
|
||||
uint64_t p_offset, p_filesz;
|
||||
|
||||
if (is_elf32) {
|
||||
elf32_program_header* ph32_array = (elf32_program_header*)outPhdrs;
|
||||
p_offset = ph32_array[i].offset;
|
||||
p_filesz = ph32_array[i].file_size;
|
||||
}
|
||||
else {
|
||||
elf64_program_header* ph64_array = (elf64_program_header*)outPhdrs;
|
||||
p_offset = ph64_array[i].offset;
|
||||
p_filesz = ph64_array[i].file_size;
|
||||
}
|
||||
|
||||
/* Seek to the offset where this segment should be written */
|
||||
if (lseek(outputFd, p_offset, SEEK_SET) != (off_t)p_offset) {
|
||||
perror("lseek to segment offset");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Skip segments with zero file size */
|
||||
if (p_filesz == 0) {
|
||||
DEBUG_PRINT(" Segment %zu has zero filesz, skipping data write\n",
|
||||
i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Write the segment data */
|
||||
ssize_t bytes_written = write(outputFd, data_buffers[i], p_filesz);
|
||||
if (bytes_written < 0) {
|
||||
perror("write segment data");
|
||||
goto cleanup;
|
||||
}
|
||||
else if ((size_t)bytes_written != p_filesz) {
|
||||
fprintf(stderr,
|
||||
"Short write for segment %zu (expected %lu, wrote %zd)\n",
|
||||
i, (unsigned long)p_filesz, bytes_written);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
DEBUG_PRINT(" Wrote segment %zu data (0x%lx bytes at offset 0x%lx)\n",
|
||||
i, (unsigned long)p_filesz, (unsigned long)p_offset);
|
||||
}
|
||||
|
||||
/* Step 5: Write Section Header Table if not using --nosht */
|
||||
if (!noSht) {
|
||||
/* Seek to the Section Header Table offset */
|
||||
if (lseek(outputFd, sht_offset, SEEK_SET) != (off_t)sht_offset) {
|
||||
perror("lseek to SHT offset");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Write a NULL section header (all zeros) */
|
||||
if (is_elf32) {
|
||||
elf32_section_header shdr32 = {0}; /* All zeros for NULL section */
|
||||
if (write(outputFd, &shdr32, sizeof(shdr32)) != sizeof(shdr32)) {
|
||||
perror("write NULL section header");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elf64_section_header shdr64 = {0}; /* All zeros for NULL section */
|
||||
if (write(outputFd, &shdr64, sizeof(shdr64)) != sizeof(shdr64)) {
|
||||
perror("write NULL section header");
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Wrote NULL section header at offset 0x%lx\n", sht_offset);
|
||||
}
|
||||
|
||||
DEBUG_PRINT("Successfully wrote output ELF file.\n");
|
||||
|
||||
success = true;
|
||||
|
||||
cleanup:
|
||||
/* Clean up resources */
|
||||
if (data_buffers) {
|
||||
for (size_t i = 0; i < loadCount; i++) {
|
||||
free(data_buffers[i]);
|
||||
}
|
||||
free(data_buffers);
|
||||
}
|
||||
if (phdrs) {
|
||||
free(phdrs);
|
||||
}
|
||||
if (outPhdrs) {
|
||||
free(outPhdrs);
|
||||
}
|
||||
if (inputFd >= 0) {
|
||||
close(inputFd);
|
||||
}
|
||||
if (outputFd >= 0) {
|
||||
close(outputFd);
|
||||
}
|
||||
if (ranges) {
|
||||
free(ranges);
|
||||
}
|
||||
|
||||
return (success ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
|
@ -5,7 +5,6 @@ EXPVER_CMD=$(EXPVER) /dev/ttyAMA0
|
|||
BINASSEMBLE=tools/bin-assemble/bin-assemble
|
||||
SPI_CHIP=SST25VF080B
|
||||
SPI_OPTIONS=SPI_FLASH=1 WOLFBOOT_PARTITION_SIZE=0x80000 WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x00000 WOLFBOOT_PARTITION_SWAP_ADDRESS=0x80000
|
||||
SIGN_ARGS=
|
||||
SIGN_ENC_ARGS=
|
||||
DELTA_DATA_SIZE?=2000
|
||||
|
||||
|
@ -21,49 +20,6 @@ else
|
|||
SIGN_TOOL="$(WOLFBOOT_ROOT)/tools/keytools/sign"
|
||||
endif
|
||||
|
||||
# Make sign algorithm argument
|
||||
ifeq ($(SIGN),NONE)
|
||||
SIGN_ARGS+=--no-sign
|
||||
endif
|
||||
ifeq ($(SIGN),ED25519)
|
||||
SIGN_ARGS+= --ed25519
|
||||
endif
|
||||
ifeq ($(SIGN),ED448)
|
||||
SIGN_ARGS+= --ed448
|
||||
endif
|
||||
ifeq ($(SIGN),ECC256)
|
||||
SIGN_ARGS+= --ecc256
|
||||
endif
|
||||
ifeq ($(SIGN),RSA2048)
|
||||
SIGN_ARGS+= --rsa2048
|
||||
endif
|
||||
ifeq ($(SIGN),RSA3072)
|
||||
SIGN_ARGS+= --rsa3072
|
||||
endif
|
||||
ifeq ($(SIGN),RSA4096)
|
||||
SIGN_ARGS+= --rsa4096
|
||||
endif
|
||||
ifeq ($(SIGN),LMS)
|
||||
SIGN_ARGS+= --lms
|
||||
endif
|
||||
ifeq ($(SIGN),XMSS)
|
||||
SIGN_ARGS+= --xmss
|
||||
endif
|
||||
ifeq ($(SIGN),ML_DSA)
|
||||
SIGN_ARGS+= --ml_dsa
|
||||
endif
|
||||
|
||||
# Make sign hash argument
|
||||
ifeq ($(HASH),SHA256)
|
||||
SIGN_ARGS+= --sha256
|
||||
endif
|
||||
ifeq ($(HASH),SHA384)
|
||||
SIGN_ARGS+= --sha384
|
||||
endif
|
||||
ifeq ($(HASH),SHA3)
|
||||
SIGN_ARGS+= --sha3
|
||||
endif
|
||||
|
||||
ifeq ($(FLAGS_INVERT),1)
|
||||
INVERSION=
|
||||
else
|
||||
|
@ -138,7 +94,7 @@ test-spi-off: FORCE
|
|||
|
||||
test-update: test-app/image.bin FORCE
|
||||
@dd if=/dev/zero bs=131067 count=1 2>/dev/null $(INVERSION) > test-update.bin
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_ARGS) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
@dd if=test-app/image_v$(TEST_UPDATE_VERSION)_signed.bin of=test-update.bin bs=1 conv=notrunc
|
||||
@printf "pBOOT" >> test-update.bin
|
||||
@make test-reset
|
||||
|
@ -174,7 +130,7 @@ test-sim-external-flash-with-enc-delta-update-extradata: wolfboot.bin test-app/i
|
|||
$(Q)make -C test-app delta-extra-data DELTA_DATA_SIZE=$(DELTA_DATA_SIZE)
|
||||
$(Q)cp test-app/image_v1_signed.bak test-app/image_v1_signed.bin
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(SIGN_ENC_ARGS) test-app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_ARGS) $(DELTA_UPDATE_OPTIONS) $(SIGN_ENC_ARGS) \
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(DELTA_UPDATE_OPTIONS) $(SIGN_ENC_ARGS) \
|
||||
test-app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_PARTITION_SIZE))) count=1 2>/dev/null $(INVERSION) > v1_part.dd
|
||||
$(Q)dd if=test-app/image_v1_signed.bin bs=256 of=v1_part.dd conv=notrunc
|
||||
|
@ -192,11 +148,16 @@ test-sim-external-flash-with-enc-update: wolfboot.bin test-app/image.elf FORCE
|
|||
$(Q)cp test-app/image.elf test-app/image.bak.elf
|
||||
$(Q)dd if=/dev/urandom of=test-app/image.elf bs=1k count=16 oflag=append conv=notrunc
|
||||
@printf "0123456789abcdef0123456789abcdef0123456789abcdef" > /tmp/enc_key.der
|
||||
# First sign command: Create version 1 of the encrypted application (base image)
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(SIGN_ENC_ARGS) test-app/image.elf $(PRIVATE_KEY) 1
|
||||
$(Q)cp test-app/image.bak.elf test-app/image.elf
|
||||
$(Q)dd if=/dev/urandom of=test-app/image.elf bs=1k count=16 oflag=append conv=notrunc
|
||||
# Second sign command: Create a full encrypted update (version 2 by default)
|
||||
# This produces image_v2_signed_and_encrypted.bin which is needed for the first flash assembly step
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(SIGN_ENC_ARGS) test-app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_ARGS) $(DELTA_UPDATE_OPTIONS) $(SIGN_ENC_ARGS) \
|
||||
# Third sign command: Create update with delta option (if specified), producing image_v2_signed_diff_encrypted.bin
|
||||
# This file is used by the test-sim-external-flash-with-enc-delta-update target
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(DELTA_UPDATE_OPTIONS) $(SIGN_ENC_ARGS) \
|
||||
test-app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
# Assembling internal flash image
|
||||
#
|
||||
|
@ -210,6 +171,9 @@ test-sim-external-flash-with-enc-update: wolfboot.bin test-app/image.elf FORCE
|
|||
$(WOLFBOOT_PARTITION_SIZE) erased_sec.dd
|
||||
|
||||
test-sim-external-flash-with-enc-delta-update:
|
||||
# This target first calls test-sim-external-flash-with-enc-update to generate both
|
||||
# image_v2_signed_and_encrypted.bin (full update) and image_v2_signed_diff_encrypted.bin (delta update)
|
||||
# Then it rebuilds the external flash image using the delta update version
|
||||
make test-sim-external-flash-with-enc-update DELTA_UPDATE_OPTIONS="--delta test-app/image_v1_signed.bin"
|
||||
$(Q)$(BINASSEMBLE) external_flash.dd 0 test-app/image_v$(TEST_UPDATE_VERSION)_signed_diff_encrypted.bin \
|
||||
$(WOLFBOOT_PARTITION_SIZE) erased_sec.dd
|
||||
|
@ -217,12 +181,17 @@ test-sim-external-flash-with-enc-delta-update:
|
|||
test-sim-internal-flash-with-update: wolfboot.bin test-app/image.elf FORCE
|
||||
$(Q)cp test-app/image.elf test-app/image.bak.elf
|
||||
$(Q)dd if=/dev/urandom of=test-app/image.elf bs=1k count=16 oflag=append conv=notrunc
|
||||
# Create version 1 of the application (base image)
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) test-app/image.elf $(PRIVATE_KEY) 1
|
||||
$(Q)cp test-app/image.bak.elf test-app/image.elf
|
||||
$(Q)dd if=/dev/urandom of=test-app/image.elf bs=1k count=16 oflag=append conv=notrunc
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) test-app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
$(Q)dd if=/dev/zero bs=$$(($(WOLFBOOT_SECTOR_SIZE))) count=1 2>/dev/null $(INVERSION) > erased_sec.dd
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_ARGS) $(DELTA_UPDATE_OPTIONS) \
|
||||
# Sign the update image (version 2 by default)
|
||||
# This command handles both standard and delta update modes based on DELTA_UPDATE_OPTIONS
|
||||
# empty DELTA_UPDATE_OPTIONS (Without --delta): Produces image_v2_signed.bin
|
||||
# DELTA_UPDATE_OPTIONS="--delta test-app/image_v1_signed.bin": Produces image_v2_signed_diff.bin
|
||||
$(Q)$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) $(DELTA_UPDATE_OPTIONS) \
|
||||
test-app/image.elf $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
$(Q)$(BINASSEMBLE) internal_flash.dd \
|
||||
0 wolfboot.bin \
|
||||
|
@ -231,6 +200,9 @@ test-sim-internal-flash-with-update: wolfboot.bin test-app/image.elf FORCE
|
|||
$$(($(WOLFBOOT_PARTITION_SWAP_ADDRESS)-$(ARCH_FLASH_OFFSET))) erased_sec.dd
|
||||
|
||||
test-sim-internal-flash-with-delta-update:
|
||||
# This target calls test-sim-internal-flash-with-update with the delta option
|
||||
# The delta option causes the sign tool to produce image_v2_signed_diff.bin instead of image_v2_signed.bin
|
||||
# Then it rebuilds the internal flash image using the delta update version
|
||||
make test-sim-internal-flash-with-update DELTA_UPDATE_OPTIONS="--delta test-app/image_v1_signed.bin"
|
||||
$(Q)$(BINASSEMBLE) internal_flash.dd \
|
||||
0 wolfboot.bin \
|
||||
|
@ -247,6 +219,9 @@ test-sim-internal-flash-with-delta-update-no-base-sha:
|
|||
$$(($(WOLFBOOT_PARTITION_SWAP_ADDRESS)-$(ARCH_FLASH_OFFSET))) erased_sec.dd
|
||||
|
||||
test-sim-internal-flash-with-wrong-delta-update:
|
||||
# This target tests the bootloader's ability to reject delta updates with wrong base hashes
|
||||
# First it creates a delta update based on v1, then creates a different delta update based on v2
|
||||
# The final image contains v1 as the base image but a delta update that expects v2 as its base
|
||||
make test-sim-internal-flash-with-update DELTA_UPDATE_OPTIONS="--delta test-app/image_v1_signed.bin"
|
||||
make test-sim-internal-flash-with-update DELTA_UPDATE_OPTIONS="--delta test-app/image_v2_signed.bin" TEST_UPDATE_VERSION=3
|
||||
$(Q)$(BINASSEMBLE) internal_flash.dd \
|
||||
|
@ -268,12 +243,12 @@ test-sim-rollback-flash: wolfboot.elf test-sim-internal-flash-with-update FORCE
|
|||
test-self-update: FORCE
|
||||
@mv $(PRIVATE_KEY) private_key.old
|
||||
@make clean factory.bin RAM_CODE=1 WOLFBOOT_VERSION=1 SIGN=$(SIGN)
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_ARGS) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
@st-flash --reset write test-app/image_v2_signed.bin 0x08020000 || \
|
||||
(make test-reset && sleep 1 && st-flash --reset write test-app/image_v2_signed.bin 0x08020000) || \
|
||||
(make test-reset && sleep 1 && st-flash --reset write test-app/image_v2_signed.bin 0x08020000)
|
||||
@dd if=/dev/zero bs=131067 count=1 2>/dev/null $(INVERSION) > test-self-update.bin
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_ARGS) --wolfboot-update wolfboot.bin private_key.old $(WOLFBOOT_VERSION)
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) --wolfboot-update wolfboot.bin private_key.old $(WOLFBOOT_VERSION)
|
||||
@dd if=wolfboot_v$(WOLFBOOT_VERSION)_signed.bin of=test-self-update.bin bs=1 conv=notrunc
|
||||
@printf "pBOOT" >> test-self-update.bin
|
||||
@st-flash --reset write test-self-update.bin 0x08040000 || \
|
||||
|
@ -281,7 +256,7 @@ test-self-update: FORCE
|
|||
(make test-reset && sleep 1 && st-flash --reset write test-self-update.bin 0x08040000)
|
||||
|
||||
test-update-ext: test-app/image.bin FORCE
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_ARGS) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
@$(SIGN_ENV) $(SIGN_TOOL) $(SIGN_OPTIONS) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION)
|
||||
@(dd if=/dev/zero bs=1M count=1 | tr '\000' '\377' > test-update.rom)
|
||||
@dd if=test-app/image_v$(TEST_UPDATE_VERSION)_signed.bin of=test-update.rom bs=1 count=524283 conv=notrunc
|
||||
@printf "pBOOT" | dd of=test-update.rom obs=1 seek=524283 count=5 conv=notrunc
|
||||
|
@ -994,13 +969,13 @@ test-size-all:
|
|||
make clean
|
||||
make test-size SIGN=ECC256 NO_ASM=1 LIMIT=13536 NO_ARM_ASM=1
|
||||
make keysclean
|
||||
make test-size SIGN=RSA2048 LIMIT=11232 NO_ARM_ASM=1
|
||||
make test-size SIGN=RSA2048 LIMIT=11272 NO_ARM_ASM=1
|
||||
make clean
|
||||
make test-size SIGN=RSA2048 NO_ASM=1 LIMIT=11808 NO_ARM_ASM=1
|
||||
make test-size SIGN=RSA2048 NO_ASM=1 LIMIT=11840 NO_ARM_ASM=1
|
||||
make keysclean
|
||||
make test-size SIGN=RSA4096 LIMIT=11520 NO_ARM_ASM=1
|
||||
make test-size SIGN=RSA4096 LIMIT=11556 NO_ARM_ASM=1
|
||||
make clean
|
||||
make test-size SIGN=RSA4096 NO_ASM=1 LIMIT=12096 NO_ARM_ASM=1
|
||||
make test-size SIGN=RSA4096 NO_ASM=1 LIMIT=12128 NO_ARM_ASM=1
|
||||
make keysclean
|
||||
make test-size SIGN=ECC384 LIMIT=17556 NO_ARM_ASM=1
|
||||
make clean
|
||||
|
@ -1008,9 +983,9 @@ test-size-all:
|
|||
make keysclean
|
||||
make test-size SIGN=ED448 LIMIT=13464 NO_ARM_ASM=1
|
||||
make keysclean
|
||||
make test-size SIGN=RSA3072 LIMIT=11372 NO_ARM_ASM=1
|
||||
make test-size SIGN=RSA3072 LIMIT=11408 NO_ARM_ASM=1
|
||||
make clean
|
||||
make test-size SIGN=RSA3072 NO_ASM=1 LIMIT=11912 NO_ARM_ASM=1
|
||||
make test-size SIGN=RSA3072 NO_ASM=1 LIMIT=11944 NO_ARM_ASM=1
|
||||
make keysclean
|
||||
make test-size SIGN=LMS LMS_LEVELS=2 LMS_HEIGHT=5 LMS_WINTERNITZ=8 \
|
||||
WOLFBOOT_SMALL_STACK=0 IMAGE_SIGNATURE_SIZE=2644 \
|
||||
|
|
Loading…
Reference in New Issue