mirror of https://github.com/wolfSSL/wolfBoot.git
Merge pull request #574 from bigbrett/wolfhsm-cert-verify
Add cert chain verification via wolfHSM on sim and TC3xxpull/573/merge
commit
0bf65fabb3
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,6 +10,7 @@ This example demonstrates using wolfBoot on the Infineon AURIX TC3xx family of m
|
|||
- [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)
|
||||
|
@ -23,6 +24,9 @@ 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)
|
||||
|
@ -95,6 +99,10 @@ Different linker script templates are used to configure the memory layout via `w
|
|||
- [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.
|
||||
|
@ -320,6 +328,27 @@ IDE/AURIX/wolfHSM-infineon-tc3xx/
|
|||
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
|
||||
|
||||
The following pseudo command sequence shows a brief overview of the commands needed to build wolfBoot on AURIX (optionally with wolfHSM). The signature and hashing algorithms used in the example are ECC 256 and SHA 256 and specified explicitly for clarity. Note that these algorithms are the default, so do not need to be explicitly specified. Optional arguments are shown in square brackets (e.g. if targeting wolfHSM, the `--hsm` option must be provided as a global option to `wbaurixtool.sh`).
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -7,4 +7,5 @@
|
|||
@ML_DSA_LEVEL@
|
||||
@ML_DSA_IMAGE_SIGNATURE_SIZE@
|
||||
@WOLFBOOT_ELF@
|
||||
@WOLFBOOT_ELF_FLASH_SCATTER@
|
||||
@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
2
Makefile
2
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
|
||||
|
@ -390,6 +391,7 @@ utilsclean: 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
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -221,3 +221,26 @@ 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.
|
||||
|
|
|
@ -665,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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -161,6 +161,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);
|
||||
|
|
|
@ -79,6 +79,7 @@ extern "C" {
|
|||
#define HDR_SIGNATURE 0x20
|
||||
#define HDR_POLICY_SIGNATURE 0x21
|
||||
#define HDR_SECONDARY_SIGNATURE 0x22
|
||||
#define HDR_CERT_CHAIN 0x23
|
||||
#define HDR_PADDING 0xFF
|
||||
|
||||
/* Auth Key types */
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ea4c3db1e05b878f39c107b375c4c57ac93ab35a
|
||||
Subproject commit f76701294bb8be47c7a9364a1061483c9ed7b3af
|
|
@ -1 +1 @@
|
|||
Subproject commit b077c81eb635392e694ccedbab8b644297ec0285
|
||||
Subproject commit 2151a1b8a1f8f81c4dba985429d50b76db7307e5
|
38
options.mk
38
options.mk
|
@ -907,5 +907,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
|
||||
|
|
116
src/image.c
116
src/image.c
|
@ -55,6 +55,12 @@
|
|||
/* Globals */
|
||||
static uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE];
|
||||
|
||||
#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)
|
||||
#ifdef ECC_IMAGE_SIGNATURE_SIZE
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1901,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);
|
||||
|
@ -1955,6 +2030,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.
|
||||
|
|
|
@ -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,10 @@ 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"
|
||||
|
@ -93,30 +95,11 @@ 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
|
||||
|
@ -130,6 +113,80 @@ 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]]"
|
||||
|
@ -142,11 +199,14 @@ usage() {
|
|||
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"
|
||||
|
@ -157,12 +217,16 @@ 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"
|
||||
|
@ -174,28 +238,29 @@ usage() {
|
|||
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
|
||||
|
@ -218,7 +283,7 @@ do_sign() {
|
|||
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"
|
||||
|
@ -226,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
|
||||
|
@ -303,7 +376,8 @@ 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=""
|
||||
|
@ -312,6 +386,7 @@ do_gen_macros() {
|
|||
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,,}]:-}"
|
||||
|
@ -326,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"
|
||||
|
@ -373,6 +455,7 @@ do_gen_macros() {
|
|||
-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
|
||||
|
@ -381,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"
|
||||
|
@ -412,7 +502,7 @@ do_gen_lcf() {
|
|||
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" \
|
||||
|
@ -479,7 +569,7 @@ while [[ $# -gt 0 ]]; do
|
|||
;;
|
||||
nvm)
|
||||
OPERATIONS+=("nvm")
|
||||
CURRENT_OPTS=""
|
||||
CURRENT_OPTS="NVM_OPTS"
|
||||
shift
|
||||
;;
|
||||
lcf)
|
||||
|
@ -546,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
|
||||
|
@ -559,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
|
||||
|
|
|
@ -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
|
|
@ -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