Add support for auxillary algorithms and cert chain/TPM usage

pull/829/head
Brett Nicholas 2026-07-09 11:25:39 -07:00 committed by Daniele Lacamera
parent 88c0f1fd55
commit 235bd820e6
11 changed files with 540 additions and 133 deletions

View File

@ -804,6 +804,34 @@ jobs:
arch: host
config-file: ./config/examples/sim-wolfHSM-server-certchain-rsa4096.config
sim_wolfhsm_server_certchain_rsa2048_ca_test:
uses: ./.github/workflows/test-build.yml
with:
arch: host
config-file: ./config/examples/sim-wolfHSM-server-certchain-rsa2048-ca.config
# Auxiliary algorithms (AUX_PK_ALGOS/AUX_HASH_ALGOS) compile-only matrix
sim_aux_algos_ed25519_rsa_ecc_test:
uses: ./.github/workflows/test-build.yml
with:
arch: host
config-file: ./config/examples/sim.config
make-args: AUX_PK_ALGOS=rsa4096,ecc384 AUX_HASH_ALGOS=sha384,sha512
sim_aux_algos_multi_rsa_test:
uses: ./.github/workflows/test-build.yml
with:
arch: host
config-file: ./config/examples/sim.config
make-args: SIGN=RSA2048 AUX_PK_ALGOS=rsa4096,rsapss2048,ecc521,ed448 AUX_HASH_ALGOS=sha3
sim_aux_algos_tpm_fallback_test:
uses: ./.github/workflows/test-build.yml
with:
arch: host
config-file: ./config/examples/sim.config
make-args: WOLFTPM=1 SIM_TPM=1
rp2350_test:
uses: ./.github/workflows/test-build-pico-sdk.yml
with:

View File

@ -44,6 +44,11 @@ jobs:
needs_posix_server: false
posix_server_nvminit: false
needs_nvm_image: true
- name: "wolfHSM server cert chain verify RSA2048/SHA384 CA, ECC256 leaf"
file: "config/examples/sim-wolfHSM-server-certchain-rsa2048-ca.config"
needs_posix_server: false
posix_server_nvminit: false
needs_nvm_image: true
fail-fast: false

View File

@ -432,7 +432,7 @@ ifeq ($(USER_PRIVATE_KEY),)
$(Q)(test $(SIGN) = NONE) || ($(SIGN_ENV) "$(KEYGEN_TOOL)" $(KEYGEN_OPTIONS) -g wolfboot_signing_private_key.der) || 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 "$(USER_CERT_CHAIN)" != "") || (tools/scripts/sim-gen-dummy-chain.sh --algo $(CERT_CHAIN_GEN_ALGO) --leaf wolfboot_signing_private_key.der)
$(Q)(test $(SIGN) = NONE) || (test "$(CERT_CHAIN_VERIFY)" = "") || (test "$(USER_CERT_CHAIN)" != "") || (tools/scripts/sim-gen-dummy-chain.sh --leaf-algo $(CERT_CHAIN_GEN_LEAF_ALGO) --ca-algo $(CERT_CHAIN_GEN_CA_ALGO) --ca-hash $(CERT_CHAIN_GEN_CA_HASH) --leaf wolfboot_signing_private_key.der)
else
@echo "Using user-provided private key: $(USER_PRIVATE_KEY)"
endif

View File

@ -0,0 +1,36 @@
ARCH=sim
TARGET=sim
SIGN?=ECC256
HASH?=SHA256
WOLFBOOT_SMALL_STACK?=0
SPI_FLASH=0
DEBUG=0
SPMATH=1
# Cert chain options: leaf follows SIGN (ecc256), CA certs use RSA2048
# signed with SHA-384. The CA algorithms are compiled in automatically
# through AUX_PK_ALGOS/AUX_HASH_ALGOS.
CERT_CHAIN_VERIFY=1
CERT_CHAIN_GEN_CA_ALGO=rsa2048
CERT_CHAIN_GEN_CA_HASH=sha384
# Ensure header is large enough to hold the cert chain (check sign tool output)
# for actual length
IMAGE_HEADER_SIZE=4096
# wolfHSM options
WOLFHSM_SERVER=1
# sizes should be multiple of system page size
WOLFBOOT_PARTITION_SIZE=0x200000
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=0x280000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x480000
# required for keytools
WOLFBOOT_FIXED_PARTITIONS=1
# For debugging XMALLOC/XFREE
#CFLAGS_EXTRA+=-DWOLFBOOT_DEBUG_MALLOC

View File

@ -21,6 +21,12 @@ In wolfBoot we support TPM based root of trust, sealing/unsealing, cryptographic
| (header macro) | `WOLFBOOT_TPM_MFG_AIK_AUTH` / `WOLFBOOT_TPM_MFG_EH_AUTH` | Default (precomputed) mode: the 16-byte per-device AIK / EH authValues (placeholder `0xFF` default). |
| (header macro) | `WOLFBOOT_TPM_MFG_EH_MASTER` | Derive mode: override the endorsement-hierarchy master value (16-byte initializer list, sample default). |
The TPM primary key (SRK) and parameter encryption need ECC or RSA in
wolfCrypt. When `WOLFTPM=1` and neither `SIGN`, `SIGN_SECONDARY`, nor
`AUX_PK_ALGOS` provides one (e.g. `SIGN=ML_DSA` or `SIGN=ED25519`), the build
automatically adds `ecc256` to `AUX_PK_ALGOS`. See "Auxiliary crypto
algorithms" in [docs/compile.md](compile.md).
## TPM manufacturing identity (IAK / IDevID authValue)
When `WOLFTPM_MFG_IDENTITY` is enabled, `wolfBoot_tpm2_get_aik()` and

View File

@ -142,6 +142,49 @@ It's possible to disable authentication of the firmware image by explicitly usin
in the Makefile commandline. This will compile a minimal bootloader with no support for public-key authenticated
secure boot.
### Auxiliary crypto algorithms
Some features need crypto algorithms beyond the ones selected with `SIGN` and
`HASH`: certificate-chain verification may meet CA certificates signed with a
different algorithm than the leaf, and TPM support needs ECC or RSA for its
primary key and parameter encryption even when `SIGN` is a post-quantum or
Ed25519/Ed448 algorithm.
`AUX_PK_ALGOS` and `AUX_HASH_ALGOS` compile extra wolfCrypt algorithms into
wolfBoot for those uses. Both take a comma-separated, case-insensitive list
(no spaces):
```sh
make SIGN=ECC256 AUX_PK_ALGOS=rsa2048,ecc384 AUX_HASH_ALGOS=sha384
```
Valid `AUX_PK_ALGOS` entries: `ecc256`, `ecc384`, `ecc521`, `rsa2048`,
`rsa3072`, `rsa4096`, `rsapss2048`, `rsapss3072`, `rsapss4096`, `ed25519`,
`ed448`. Valid `AUX_HASH_ALGOS` entries: `sha256`, `sha384`, `sha512`,
`sha3`. Post-quantum algorithms (ML-DSA, LMS, XMSS) are not yet supported as
auxiliary algorithms.
Auxiliary algorithms are never used to verify the firmware image signature;
that remains bound to `SIGN` (and `SIGN_SECONDARY` for hybrid mode). Each
entry defines a `WOLFBOOT_AUX_PK_<ALGO>` or `WOLFBOOT_AUX_HASH_<ALGO>` macro
and links the matching wolfCrypt objects; entries already covered by
`SIGN`/`SIGN_SECONDARY` are no-ops.
Notes:
- Not compatible with `WOLFBOOT_SMALL_STACK=1`: the static memory pools are
sized for the primary `SIGN` algorithm only.
- `STACK_USAGE` is not adjusted automatically. If an auxiliary algorithm with
larger stack needs (e.g. `rsa4096`) is actually exercised, consider
`WOLFBOOT_HUGE_STACK=1` (the RSA4096 cert-chain configurations already do).
- When `WOLFTPM=1` and neither `SIGN`, `SIGN_SECONDARY`, nor `AUX_PK_ALGOS`
provides an ECC or RSA algorithm, `ecc256` is added automatically so the
TPM SRK and parameter encryption work.
- With `CERT_CHAIN_VERIFY=1`, the generated dummy chain's CA algorithms
(`CERT_CHAIN_GEN_CA_ALGO`/`CERT_CHAIN_GEN_CA_HASH`) are bridged into these
lists automatically. Users providing `USER_CERT_CHAIN` must list their
chain's algorithms here themselves.
### Incremental updates
wolfBoot support incremental updates. To enable this feature, compile with `DELTA_UPDATES=1`.

View File

@ -62,10 +62,25 @@ To use certificate verification with wolfHSM:
3. Pre-provision one or more root CA certificates on the wolfHSM server at the NVM IDs listed in the HAL `hsmNvmIdCertRootCAList`. Verification succeeds if the embedded chain anchors to *any* root in the list (absent NVM IDs are silently skipped). The list length must not exceed `WOLFHSM_CFG_CERT_MAX_VERIFY_ROOTS` (default 8).
4. Sign firmware images with the `--cert-chain` option, providing a DER-encoded certificate chain
The chain's CA certificates do not need to use the same algorithm as the leaf
(which wraps the wolfBoot signing key and therefore follows `SIGN`). The
verifier only needs the CA algorithms compiled in, via `AUX_PK_ALGOS` and
`AUX_HASH_ALGOS` (see [docs/compile.md](compile.md)):
- When the build auto-generates the dummy test chain (no `USER_CERT_CHAIN`),
the CA key algorithm and cert signature hash can be chosen with
`CERT_CHAIN_GEN_CA_ALGO` (`ecc256`/`ecc384`/`ecc521`/`rsa2048`/`rsa3072`/
`rsa4096`, default: same as the leaf) and `CERT_CHAIN_GEN_CA_HASH`
(`sha256`/`sha384`/`sha512`, default `sha256`). Both are bridged into the
auxiliary algorithm lists automatically.
- When providing `USER_CERT_CHAIN`, set `AUX_PK_ALGOS`/`AUX_HASH_ALGOS` to
cover every algorithm used by the chain's certificate signatures.
To build the simulator using wolfHSM for certificate verification:
- **Client Mode**: Use [config/examples/sim-wolfHSM-client-certchain.config](config/examples/sim-wolfHSM-client-certchain.config)
- **Server Mode**: Use [config/examples/sim-wolfHSM-server-certchain.config](config/examples/sim-wolfHSM-server-certchain.config)
- **Server Mode, mixed-algorithm chain**: Use [config/examples/sim-wolfHSM-server-certchain-rsa2048-ca.config](../config/examples/sim-wolfHSM-server-certchain-rsa2048-ca.config) (RSA2048/SHA-384 CA certs, ECC256 leaf)
## Configuration Options

View File

@ -73,8 +73,80 @@ extern int tolower(int c);
#define CUSTOM_RAND_GENERATE_SEED hal_trng_get_entropy
#endif
/* Algorithm inclusion union.
* An algorithm's wolfCrypt code is compiled in when it is the primary
* (WOLFBOOT_SIGN_*), secondary (WOLFBOOT_SIGN_SECONDARY_*), or auxiliary
* (WOLFBOOT_AUX_PK_* / WOLFBOOT_AUX_HASH_*, from the AUX_PK_ALGOS and
* AUX_HASH_ALGOS build options) algorithm. Auxiliary algorithms serve
* features like cert-chain verification and TPM; they are never used to
* verify image signatures, which stay keyed on WOLFBOOT_SIGN_*.
* The WOLFBOOT_ENABLE_* macros below are internal to this file. */
#if defined(WOLFBOOT_SIGN_ECC256) || defined(WOLFBOOT_SIGN_SECONDARY_ECC256) \
|| defined(WOLFBOOT_AUX_PK_ECC256)
# define WOLFBOOT_ENABLE_PK_ECC256
#endif
#if defined(WOLFBOOT_SIGN_ECC384) || defined(WOLFBOOT_SIGN_SECONDARY_ECC384) \
|| defined(WOLFBOOT_AUX_PK_ECC384)
# define WOLFBOOT_ENABLE_PK_ECC384
#endif
#if defined(WOLFBOOT_SIGN_ECC521) || defined(WOLFBOOT_SIGN_SECONDARY_ECC521) \
|| defined(WOLFBOOT_AUX_PK_ECC521)
# define WOLFBOOT_ENABLE_PK_ECC521
#endif
#if defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) \
|| defined(WOLFBOOT_AUX_PK_RSA2048)
# define WOLFBOOT_ENABLE_PK_RSA2048
#endif
#if defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) \
|| defined(WOLFBOOT_AUX_PK_RSA3072)
# define WOLFBOOT_ENABLE_PK_RSA3072
#endif
#if defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSA4096) \
|| defined(WOLFBOOT_AUX_PK_RSA4096)
# define WOLFBOOT_ENABLE_PK_RSA4096
#endif
#if defined(WOLFBOOT_SIGN_RSAPSS2048) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS2048) || \
defined(WOLFBOOT_AUX_PK_RSAPSS2048)
# define WOLFBOOT_ENABLE_PK_RSAPSS2048
#endif
#if defined(WOLFBOOT_SIGN_RSAPSS3072) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS3072) || \
defined(WOLFBOOT_AUX_PK_RSAPSS3072)
# define WOLFBOOT_ENABLE_PK_RSAPSS3072
#endif
#if defined(WOLFBOOT_SIGN_RSAPSS4096) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS4096) || \
defined(WOLFBOOT_AUX_PK_RSAPSS4096)
# define WOLFBOOT_ENABLE_PK_RSAPSS4096
#endif
#if defined(WOLFBOOT_SIGN_ED25519) || defined(WOLFBOOT_SIGN_SECONDARY_ED25519) \
|| defined(WOLFBOOT_AUX_PK_ED25519)
# define WOLFBOOT_ENABLE_PK_ED25519
#endif
#if defined(WOLFBOOT_SIGN_ED448) || defined(WOLFBOOT_SIGN_SECONDARY_ED448) \
|| defined(WOLFBOOT_AUX_PK_ED448)
# define WOLFBOOT_ENABLE_PK_ED448
#endif
/* Hash inclusion: the primary image hash plus any auxiliary hashes.
* SHA-256 is the default image hash when no other primary hash is set. */
#if defined(WOLFBOOT_AUX_HASH_SHA256) || \
(!defined(WOLFBOOT_HASH_SHA384) && !defined(WOLFBOOT_HASH_SHA3_384))
# define WOLFBOOT_ENABLE_HASH_SHA256
#endif
#if defined(WOLFBOOT_HASH_SHA384) || defined(WOLFBOOT_AUX_HASH_SHA384)
# define WOLFBOOT_ENABLE_HASH_SHA384
#endif
#ifdef WOLFBOOT_AUX_HASH_SHA512
# define WOLFBOOT_ENABLE_HASH_SHA512
#endif
#if defined(WOLFBOOT_HASH_SHA3_384) || defined(WOLFBOOT_AUX_HASH_SHA3)
# define WOLFBOOT_ENABLE_HASH_SHA3
#endif
/* ED25519 and SHA512 */
#if defined(WOLFBOOT_SIGN_ED25519) || defined(WOLFBOOT_SIGN_SECONDARY_ED25519)
#ifdef WOLFBOOT_ENABLE_PK_ED25519
# define HAVE_ED25519
# define ED25519_SMALL
# if !defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)
@ -86,7 +158,7 @@ extern int tolower(int c);
#endif
/* ED448 and SHA3/SHAKE256 */
#if defined(WOLFBOOT_SIGN_ED448) || defined(WOLFBOOT_SIGN_SECONDARY_ED448)
#ifdef WOLFBOOT_ENABLE_PK_ED448
# define HAVE_ED448
# define HAVE_ED448_VERIFY
# define ED448_SMALL
@ -100,12 +172,9 @@ extern int tolower(int c);
#endif
/* ECC */
#if defined(WOLFBOOT_SIGN_ECC256) || \
defined(WOLFBOOT_SIGN_ECC384) || \
defined(WOLFBOOT_SIGN_ECC521) || \
defined(WOLFBOOT_SIGN_SECONDARY_ECC256) || \
defined(WOLFBOOT_SIGN_SECONDARY_ECC384) || \
defined(WOLFBOOT_SIGN_SECONDARY_ECC521) || \
#if defined(WOLFBOOT_ENABLE_PK_ECC256) || \
defined(WOLFBOOT_ENABLE_PK_ECC384) || \
defined(WOLFBOOT_ENABLE_PK_ECC521) || \
defined(WOLFCRYPT_SECURE_MODE) || \
defined(WOLFCRYPT_TEST) || defined(WOLFCRYPT_BENCHMARK)
@ -166,21 +235,18 @@ extern int tolower(int c);
#define WOLFSSL_PUBLIC_MP
/* Curve */
# if defined(WOLFBOOT_SIGN_ECC256) || defined(WOLFCRYPT_SECURE_MODE) || \
defined(WOLFBOOT_SIGN_SECONDARY_ECC256) || \
# if defined(WOLFBOOT_ENABLE_PK_ECC256) || defined(WOLFCRYPT_SECURE_MODE) || \
defined(WOLFCRYPT_TEST) || defined(WOLFCRYPT_BENCHMARK)
# define HAVE_ECC256
# endif
# if defined(WOLFBOOT_SIGN_ECC384) || \
defined(WOLFBOOT_SIGN_SECONDARY_ECC384) || \
# if defined(WOLFBOOT_ENABLE_PK_ECC384) || \
defined(WOLFCRYPT_SECURE_MODE) || \
defined(WOLFCRYPT_TEST) || defined(WOLFCRYPT_BENCHMARK)
# define HAVE_ECC384
# define WOLFSSL_SP_384
# endif
/* ECC521 only enabled if specifically requested (not for tests - too large) */
# if defined(WOLFBOOT_SIGN_ECC521) || \
defined(WOLFBOOT_SIGN_SECONDARY_ECC521) || \
# if defined(WOLFBOOT_ENABLE_PK_ECC521) || \
defined(WOLFCRYPT_SECURE_MODE)
# define HAVE_ECC521
# define WOLFSSL_SP_521
@ -210,24 +276,17 @@ extern int tolower(int c);
# define WOLFSSL_SP_NO_256
# endif
# endif
#endif /* WOLFBOOT_SIGN_ECC521 || WOLFBOOT_SIGN_ECC384 || WOLFBOOT_SIGN_ECC256 ||
* WOLFBOOT_SIGN_SECONDARY_ECC521 || WOLFBOOT_SIGN_SECONDARY_ECC384 ||
* WOLFBOOT_SIGN_SECONDARY_ECC256 || WOLFCRYPT_SECURE_MODE */
#endif /* WOLFBOOT_ENABLE_PK_ECC521 || WOLFBOOT_ENABLE_PK_ECC384 ||
* WOLFBOOT_ENABLE_PK_ECC256 || WOLFCRYPT_SECURE_MODE */
/* RSA */
#if defined(WOLFBOOT_SIGN_RSA2048) || \
defined(WOLFBOOT_SIGN_RSA3072) || \
defined(WOLFBOOT_SIGN_RSA4096) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSA4096) || \
defined(WOLFBOOT_SIGN_RSAPSS2048) || \
defined(WOLFBOOT_SIGN_RSAPSS3072) || \
defined(WOLFBOOT_SIGN_RSAPSS4096) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS2048) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS3072) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS4096) || \
#if defined(WOLFBOOT_ENABLE_PK_RSA2048) || \
defined(WOLFBOOT_ENABLE_PK_RSA3072) || \
defined(WOLFBOOT_ENABLE_PK_RSA4096) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS2048) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS3072) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS4096) || \
(defined(WOLFCRYPT_SECURE_MODE) && (!defined(PKCS11_SMALL)))
/* RSA blinding protects RSA private-key operations against timing
@ -248,11 +307,9 @@ extern int tolower(int c);
# define WC_RSA_DIRECT
# define RSA_LOW_MEM
# define WC_ASN_HASH_SHA256
# if defined(WOLFBOOT_SIGN_RSAPSS2048) || defined(WOLFBOOT_SIGN_RSAPSS3072) || \
defined(WOLFBOOT_SIGN_RSAPSS4096) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS2048) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS3072) || \
defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS4096)
# if defined(WOLFBOOT_ENABLE_PK_RSAPSS2048) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS3072) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS4096)
# define WC_RSA_PSS
# endif
# if !defined(WOLFBOOT_TPM) && !defined(WOLFCRYPT_SECURE_MODE) && \
@ -262,7 +319,11 @@ extern int tolower(int c);
# define WOLFSSL_RSA_VERIFY_INLINE
# define WOLFSSL_RSA_VERIFY_ONLY
# define WOLFSSL_RSA_PUBLIC_ONLY
# if !defined(WC_RSA_PSS)
/* With WC_NO_RSA_OAEP set, wolfssl settings.h may strip
* ConstantCompare (WOLFSSL_NO_CONST_CMP), which ed25519/ed448
* verify still needs. Keep OAEP when an Ed algo is compiled in. */
# if !defined(WC_RSA_PSS) && !defined(WOLFBOOT_ENABLE_PK_ED25519) && \
!defined(WOLFBOOT_ENABLE_PK_ED448)
# define WC_NO_RSA_OAEP
# endif
# define NO_RSA_BOUNDS_CHECK
@ -273,46 +334,59 @@ extern int tolower(int c);
# define WOLFSSL_SP_SMALL
# define WOLFSSL_SP_MATH
# endif
# if defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) || \
defined(WOLFBOOT_SIGN_RSAPSS2048) || defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS2048)
# define FP_MAX_BITS (2048 * 2)
# define SP_INT_BITS 2048
# define WOLFSSL_SP_NO_3072
# define WOLFSSL_SP_NO_4096
# define WOLFSSL_SP_2048
# define RSA_MIN_SIZE 2048
# define RSA_MAX_SIZE 2048
/* Key sizes in use (secure mode serves all of them) */
# if defined(WOLFBOOT_ENABLE_PK_RSA2048) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS2048) || defined(WOLFCRYPT_SECURE_MODE)
# define WOLFBOOT_ENABLE_RSA2048_SIZE
# endif
# if defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) || \
defined(WOLFBOOT_SIGN_RSAPSS3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS3072)
# if defined(WOLFBOOT_ENABLE_PK_RSA3072) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS3072) || defined(WOLFCRYPT_SECURE_MODE)
# define WOLFBOOT_ENABLE_RSA3072_SIZE
# endif
# if defined(WOLFBOOT_ENABLE_PK_RSA4096) || \
defined(WOLFBOOT_ENABLE_PK_RSAPSS4096) || defined(WOLFCRYPT_SECURE_MODE)
# define WOLFBOOT_ENABLE_RSA4096_SIZE
# endif
/* SP code for each selected size; strip the others */
# ifdef WOLFBOOT_ENABLE_RSA2048_SIZE
# define WOLFSSL_SP_2048
# else
# define WOLFSSL_SP_NO_2048
# endif
# ifdef WOLFBOOT_ENABLE_RSA3072_SIZE
# define WOLFSSL_SP_3072
# else
# define WOLFSSL_SP_NO_3072
# endif
# ifdef WOLFBOOT_ENABLE_RSA4096_SIZE
# define WOLFSSL_SP_4096
# else
# define WOLFSSL_SP_NO_4096
# endif
/* Math sized for the largest key; any RSA key needs more than any
* ECC curve enabled above */
# ifdef FP_MAX_BITS
# undef FP_MAX_BITS
# endif
# if defined(WOLFBOOT_ENABLE_RSA4096_SIZE)
# define FP_MAX_BITS (4096 * 2)
# define SP_INT_BITS 4096
# define RSA_MAX_SIZE 4096
# elif defined(WOLFBOOT_ENABLE_RSA3072_SIZE)
# define FP_MAX_BITS (3072 * 2)
# define SP_INT_BITS 3072
# define WOLFSSL_SP_NO_2048
# define WOLFSSL_SP_NO_4096
# define WOLFSSL_SP_3072
# define RSA_MIN_SIZE 3072
# define RSA_MAX_SIZE 3072
# elif defined(WOLFBOOT_ENABLE_RSA2048_SIZE)
# define FP_MAX_BITS (2048 * 2)
# define SP_INT_BITS 2048
# define RSA_MAX_SIZE 2048
# endif
# if defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSA4096) || \
defined(WOLFBOOT_SIGN_RSAPSS4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS4096)
# define FP_MAX_BITS (4096 * 2)
# define SP_INT_BITS 4096
# define WOLFSSL_SP_NO_2048
# define WOLFSSL_SP_NO_3072
# define WOLFSSL_SP_4096
# define RSA_MIN_SIZE 4096
# define RSA_MAX_SIZE 4096
# endif
# ifdef WOLFCRYPT_SECURE_MODE
# undef FP_MAX_BITS
# define FP_MAX_BITS (4096 * 2)
# define SP_INT_BITS 4096
# define WOLFSSL_SP_2048
# define WOLFSSL_SP_3072
# define WOLFSSL_SP_4096
# if defined(WOLFBOOT_ENABLE_RSA2048_SIZE)
# define RSA_MIN_SIZE 2048
# define RSA_MAX_SIZE 4096
# elif defined(WOLFBOOT_ENABLE_RSA3072_SIZE)
# define RSA_MIN_SIZE 3072
# elif defined(WOLFBOOT_ENABLE_RSA4096_SIZE)
# define RSA_MIN_SIZE 4096
# endif
#else
# define NO_RSA
@ -343,22 +417,16 @@ extern int tolower(int c);
# define WOLFSSL_SP_NO_DYN_STACK
#endif /* WOLFBOOT_SIGN_ML_DSA || WOLFBOOT_SIGN_SECONDARY_ML_DSA */
#ifdef WOLFBOOT_HASH_SHA3_384
#ifdef WOLFBOOT_ENABLE_HASH_SHA3
# define WOLFSSL_SHA3
# if defined(NO_RSA) && !defined(WOLFBOOT_TPM) && \
!defined(WOLFCRYPT_SECURE_MODE) && \
!defined(WOLFCRYPT_TEST) && !defined(WOLFCRYPT_BENCHMARK)
# define NO_SHA256
# endif
#endif
#ifdef WOLFBOOT_HASH_SHA384
#ifdef WOLFBOOT_ENABLE_HASH_SHA384
# define WOLFSSL_SHA384
# if defined(NO_RSA) && !defined(WOLFBOOT_TPM) && \
!defined(WOLFCRYPT_SECURE_MODE) && \
!defined(WOLFCRYPT_TEST) && !defined(WOLFCRYPT_BENCHMARK)
# define NO_SHA256
# endif
#endif
/* SHA-384 is computed through the SHA-512 core */
#if defined(WOLFBOOT_ENABLE_HASH_SHA384) || defined(WOLFBOOT_ENABLE_HASH_SHA512)
# ifndef WOLFSSL_SHA512
# define WOLFSSL_SHA512
# define WOLFSSL_NOSHA512_224
@ -366,6 +434,14 @@ extern int tolower(int c);
# endif
#endif
/* Drop SHA-256 when neither the image hash nor any other user needs it */
#if (defined(WOLFBOOT_HASH_SHA384) || defined(WOLFBOOT_HASH_SHA3_384)) && \
!defined(WOLFBOOT_ENABLE_HASH_SHA256) && defined(NO_RSA) && \
!defined(WOLFBOOT_TPM) && !defined(WOLFCRYPT_SECURE_MODE) && \
!defined(WOLFCRYPT_TEST) && !defined(WOLFCRYPT_BENCHMARK)
# define NO_SHA256
#endif
/* If SP math is enabled determine word size */
#if defined(WOLFSSL_HAVE_SP_ECC) || defined(WOLFSSL_HAVE_SP_RSA)
# ifdef __aarch64__

View File

@ -1619,25 +1619,62 @@ ifneq ($(CERT_CHAIN_VERIFY),)
CFLAGS += '-DWOLFBOOT_WOLFHSM_NVM_ROOT_CA_LIST=$(WOLFHSM_NVM_ROOT_CA_LIST)'
endif
# User-provided cert chain takes precedence
# User-provided cert chain takes precedence. Declare the chain's
# algorithms via AUX_PK_ALGOS/AUX_HASH_ALGOS so the verifier has them.
ifneq ($(USER_CERT_CHAIN),)
CERT_CHAIN_FILE = $(USER_CERT_CHAIN)
else
# Auto-generate dummy cert chain (when USER_CERT_CHAIN not provided)
CERT_CHAIN_FILE = test-dummy-ca/raw-chain.der
# Set appropriate cert gen algo based on signature algorithm
# The leaf cert wraps the signing key, so its algo follows SIGN
ifeq ($(SIGN),ECC256)
CERT_CHAIN_GEN_ALGO+=ecc256
CERT_CHAIN_GEN_LEAF_ALGO:=ecc256
endif
ifeq ($(SIGN),ECC384)
CERT_CHAIN_GEN_LEAF_ALGO:=ecc384
endif
ifeq ($(SIGN),ECC521)
CERT_CHAIN_GEN_LEAF_ALGO:=ecc521
endif
ifeq ($(SIGN),RSA2048)
CERT_CHAIN_GEN_ALGO+=rsa2048
CERT_CHAIN_GEN_LEAF_ALGO:=rsa2048
endif
ifeq ($(SIGN),RSA3072)
CERT_CHAIN_GEN_LEAF_ALGO:=rsa3072
endif
ifeq ($(SIGN),RSA4096)
CERT_CHAIN_GEN_ALGO+=rsa4096
# Reasonably large default
CFLAGS += -DWOLFHSM_CFG_MAX_CERT_SIZE=4096
CERT_CHAIN_GEN_LEAF_ALGO:=rsa4096
endif
ifeq ($(SIGN),RSAPSS2048)
CERT_CHAIN_GEN_LEAF_ALGO:=rsa2048
endif
ifeq ($(SIGN),RSAPSS3072)
CERT_CHAIN_GEN_LEAF_ALGO:=rsa3072
endif
ifeq ($(SIGN),RSAPSS4096)
CERT_CHAIN_GEN_LEAF_ALGO:=rsa4096
endif
ifeq ($(CERT_CHAIN_GEN_LEAF_ALGO),)
$(error dummy cert chain generation does not support SIGN=$(SIGN); \
provide USER_CERT_CHAIN instead)
endif
# Root/intermediate key algo and cert signature hash are configurable
CERT_CHAIN_GEN_CA_ALGO?=$(CERT_CHAIN_GEN_LEAF_ALGO)
CERT_CHAIN_GEN_CA_HASH?=sha256
# Compile in the CA's algorithms so the chain verifies in boot
ifneq ($(CERT_CHAIN_GEN_CA_ALGO),$(CERT_CHAIN_GEN_LEAF_ALGO))
AUX_PK_ALGOS:=$(AUX_PK_ALGOS),$(CERT_CHAIN_GEN_CA_ALGO)
endif
ifneq ($(CERT_CHAIN_GEN_CA_HASH),sha256)
AUX_HASH_ALGOS:=$(AUX_HASH_ALGOS),$(CERT_CHAIN_GEN_CA_HASH)
endif
endif
# Reasonably large default cert buffer when RSA4096 is in the chain
ifneq (,$(filter rsa4096,$(CERT_CHAIN_GEN_CA_ALGO) $(CERT_CHAIN_GEN_LEAF_ALGO)))
CFLAGS += -DWOLFHSM_CFG_MAX_CERT_SIZE=4096
endif
SIGN_OPTIONS += --cert-chain $(CERT_CHAIN_FILE)
endif
@ -1682,3 +1719,119 @@ endif
ifeq ($(TZEN),1)
CFLAGS+=-DTZEN
endif
# Auxiliary algorithms: compile extra wolfCrypt code beyond what SIGN/HASH
# selects, for features that need it (cert-chain verification, TPM, ...).
# Auxiliary algorithms are never used to verify image signatures.
# AUX_PK_ALGOS / AUX_HASH_ALGOS take comma-separated, case-insensitive
# entries, e.g. AUX_PK_ALGOS=rsa2048,ecc384 AUX_HASH_ALGOS=sha384.
# This section must stay below anything that appends to the two lists
# (e.g. the cert-chain block above).
AUX_PK_ALGOS?=
AUX_HASH_ALGOS?=
AUX_PK_LIST:=$(sort $(shell echo $(AUX_PK_ALGOS) | tr 'A-Z,' 'a-z '))
AUX_HASH_LIST:=$(sort $(shell echo $(AUX_HASH_ALGOS) | tr 'A-Z,' 'a-z '))
SIGN_TOKENS_LC:=$(shell echo $(SIGN) $(SIGN_SECONDARY) | tr 'A-Z' 'a-z')
# TPM needs ECC or RSA for the SRK and parameter encryption
ifeq ($(WOLFTPM),1)
ifeq (,$(filter ecc% rsa%,$(SIGN_TOKENS_LC) $(AUX_PK_LIST)))
AUX_PK_LIST+=ecc256
endif
endif
ifneq (,$(strip $(AUX_PK_LIST) $(AUX_HASH_LIST)))
ifeq ($(WOLFBOOT_SMALL_STACK),1)
$(error auxiliary algorithms not supported with WOLFBOOT_SMALL_STACK: \
the static pools in src/xmalloc.c only cover the primary SIGN algorithm)
endif
endif
AUX_PK_VALID:=ecc256 ecc384 ecc521 rsa2048 rsa3072 rsa4096 \
rsapss2048 rsapss3072 rsapss4096 ed25519 ed448
AUX_HASH_VALID:=sha256 sha384 sha512 sha3
ifneq (,$(filter-out $(AUX_PK_VALID),$(AUX_PK_LIST)))
$(error invalid AUX_PK_ALGOS entries "$(filter-out $(AUX_PK_VALID),$(AUX_PK_LIST))". Valid: $(AUX_PK_VALID))
endif
ifneq (,$(filter-out $(AUX_HASH_VALID),$(AUX_HASH_LIST)))
$(error invalid AUX_HASH_ALGOS entries "$(filter-out $(AUX_HASH_VALID),$(AUX_HASH_LIST))". Valid: $(AUX_HASH_VALID))
endif
# Entries matching SIGN/SIGN_SECONDARY are already compiled in
AUX_PK_EFFECTIVE:=$(filter-out $(SIGN_TOKENS_LC),$(AUX_PK_LIST))
AUX_WOLFCRYPT_OBJS:=
ifneq (,$(filter ecc256,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_ECC256
AUX_WOLFCRYPT_OBJS+=$(ECC_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter ecc384,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_ECC384
AUX_WOLFCRYPT_OBJS+=$(ECC_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter ecc521,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_ECC521
AUX_WOLFCRYPT_OBJS+=$(ECC_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter rsa2048,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_RSA2048
AUX_WOLFCRYPT_OBJS+=$(RSA_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter rsa3072,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_RSA3072
AUX_WOLFCRYPT_OBJS+=$(RSA_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter rsa4096,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_RSA4096
AUX_WOLFCRYPT_OBJS+=$(RSA_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter rsapss2048,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_RSAPSS2048
AUX_WOLFCRYPT_OBJS+=$(RSA_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter rsapss3072,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_RSAPSS3072
AUX_WOLFCRYPT_OBJS+=$(RSA_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter rsapss4096,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_RSAPSS4096
AUX_WOLFCRYPT_OBJS+=$(RSA_OBJS) $(MATH_OBJS)
endif
ifneq (,$(filter ed25519,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_ED25519
AUX_WOLFCRYPT_OBJS+=$(ED25519_OBJS)
endif
ifneq (,$(filter ed448,$(AUX_PK_EFFECTIVE)))
CFLAGS+=-DWOLFBOOT_AUX_PK_ED448
AUX_WOLFCRYPT_OBJS+=$(ED448_OBJS)
AUX_WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha3.o
AUX_WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha512.o
endif
# ED448 defines WOLFSSL_SHA512 in user_settings.h but ED448_OBJS carries no
# sha512.o; make sure it gets linked (deduplicated below)
ifneq (,$(filter ED448,$(SIGN) $(SIGN_SECONDARY)))
AUX_WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha512.o
endif
ifneq (,$(filter sha256,$(AUX_HASH_LIST)))
CFLAGS+=-DWOLFBOOT_AUX_HASH_SHA256
endif
ifneq (,$(filter sha384,$(AUX_HASH_LIST)))
CFLAGS+=-DWOLFBOOT_AUX_HASH_SHA384
AUX_WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha512.o
endif
ifneq (,$(filter sha512,$(AUX_HASH_LIST)))
CFLAGS+=-DWOLFBOOT_AUX_HASH_SHA512
AUX_WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha512.o
endif
ifneq (,$(filter sha3,$(AUX_HASH_LIST)))
CFLAGS+=-DWOLFBOOT_AUX_HASH_SHA3
AUX_WOLFCRYPT_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha3.o
endif
# Append only objects not already selected by SIGN/HASH/features.
# Snapshot with := first: WOLFCRYPT_OBJS is a recursive variable in some
# includers (test-app), where a self-referencing += would not terminate.
AUX_WOLFCRYPT_OBJS_NEW:=$(filter-out $(WOLFCRYPT_OBJS),$(sort $(AUX_WOLFCRYPT_OBJS)))
WOLFCRYPT_OBJS+=$(AUX_WOLFCRYPT_OBJS_NEW)

View File

@ -138,4 +138,8 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO
WOLFHSM_CLIENT \
WOLFHSM_CLIENT_ID \
WOLFHSM_NVM_ROOT_CA_LIST \
AUX_PK_ALGOS \
AUX_HASH_ALGOS \
CERT_CHAIN_GEN_CA_ALGO \
CERT_CHAIN_GEN_CA_HASH \
ENCRYPT_CACHE

View File

@ -1,61 +1,83 @@
#!/bin/bash
# Certificate Chain Generation Script (ECC P256 or RSA)
# Certificate Chain Generation Script (ECC 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
# The CA (root+intermediate) key algo, the CA cert signature hash, and the
# leaf key algo can be chosen independently.
set -e # Exit on any error
# Default output directory and algorithm
# Defaults
OUTPUT_DIR="test-dummy-ca"
ALGO="ecc256" # Default to ECC P-256 keys
LEGACY_ALGO="" # --algo: sets both CA and leaf (backward compatible)
CA_ALGO=""
LEAF_ALGO=""
CA_HASH=""
# Helper functions for key operations
VALID_ALGOS="ecc256 ecc384 ecc521 rsa2048 rsa3072 rsa4096"
VALID_HASHES="sha256 sha384 sha512"
validate_choice() {
local kind=$1 value=$2 valid=$3
for v in $valid; do
[[ "$value" == "$v" ]] && return 0
done
echo "Invalid $kind: $value. Use one of: $valid"
exit 1
}
# Helper functions for key operations (first argument selects the algorithm)
generate_private_key() {
local output_file=$1
local algo=$1
local output_file=$2
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
case "$algo" in
ecc256) openssl ecparam -genkey -name prime256v1 -noout -out "$output_file" ;;
ecc384) openssl ecparam -genkey -name secp384r1 -noout -out "$output_file" ;;
ecc521) openssl ecparam -genkey -name secp521r1 -noout -out "$output_file" ;;
rsa2048) openssl genrsa -out "$output_file" 2048 ;;
rsa3072) openssl genrsa -out "$output_file" 3072 ;;
rsa4096) openssl genrsa -out "$output_file" 4096 ;;
esac
}
convert_key_to_der() {
local input_file=$1
local output_file=$2
local algo=$1
local input_file=$2
local output_file=$3
if [[ "$ALGO" == "ecc256" ]]; then
if [[ "$algo" == ecc* ]]; then
openssl ec -in "$input_file" -outform DER -out "$output_file"
elif [[ "$ALGO" == "rsa2048" || "$ALGO" == "rsa4096" ]]; then
else
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
local algo=$1
local cert_file=$2
local pubkey_pem=$3
local pubkey_der=$4
# 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
if [[ "$algo" == ecc* ]]; then
openssl ec -pubin -in "$pubkey_pem" -outform DER -out "$pubkey_der"
elif [[ "$ALGO" == "rsa2048" || "$ALGO" == "rsa4096" ]]; then
else
openssl rsa -pubin -in "$pubkey_pem" -outform DER -out "$pubkey_der"
fi
}
validate_key_format() {
local key_file=$1
local algo=$1
local key_file=$2
if [[ "$ALGO" == "ecc256" ]]; then
if [[ "$algo" == ecc* ]]; then
openssl ec -in "$key_file" -noout
elif [[ "$ALGO" == "rsa2048" || "$ALGO" == "rsa4096" ]]; then
else
openssl rsa -in "$key_file" -noout
fi
}
@ -73,21 +95,40 @@ while [[ $# -gt 0 ]]; do
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
LEGACY_ALGO="$2"
validate_choice "algorithm" "$LEGACY_ALGO" "$VALID_ALGOS"
shift 2
;;
--ca-algo)
CA_ALGO="$2"
validate_choice "CA algorithm" "$CA_ALGO" "$VALID_ALGOS"
shift 2
;;
--leaf-algo)
LEAF_ALGO="$2"
validate_choice "leaf algorithm" "$LEAF_ALGO" "$VALID_ALGOS"
shift 2
;;
--ca-hash)
CA_HASH="$2"
validate_choice "CA hash" "$CA_HASH" "$VALID_HASHES"
shift 2
;;
*)
echo "Unknown option: $1"
echo "Usage: $0 [--leaf <private_key_file>] [--outdir <output_directory>] [--algo <ecc256|rsa2048|rsa4096>]"
echo "Usage: $0 [--leaf <private_key_file>] [--outdir <output_directory>]" \
"[--algo <alg>] [--ca-algo <alg>] [--leaf-algo <alg>] [--ca-hash <sha256|sha384|sha512>]"
echo " <alg>: $VALID_ALGOS"
exit 1
;;
esac
done
# --algo sets both unless overridden; default ecc256
CA_ALGO="${CA_ALGO:-${LEGACY_ALGO:-ecc256}}"
LEAF_ALGO="${LEAF_ALGO:-${LEGACY_ALGO:-ecc256}}"
CA_HASH="${CA_HASH:-sha256}"
# 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"
@ -100,14 +141,14 @@ mkdir -p ${OUTPUT_DIR}/temp
##################
# GENERATE CHAIN
##################
echo "Generating Certificate Chain using $ALGO..."
echo "Generating Certificate Chain (CA: $CA_ALGO/$CA_HASH, leaf: $LEAF_ALGO)..."
# Step 1: Generate Root key and certificate
echo "Generating Root CA..."
generate_private_key "${OUTPUT_DIR}/temp/root.key.pem"
generate_private_key "$CA_ALGO" "${OUTPUT_DIR}/temp/root.key.pem"
# Create PEM format root certificate (temporary)
openssl req -new -x509 -days 3650 -sha256 \
openssl req -new -x509 -days 3650 -$CA_HASH \
-key ${OUTPUT_DIR}/temp/root.key.pem \
-out ${OUTPUT_DIR}/temp/root.crt.pem \
-subj "$ROOT_SUBJECT" \
@ -115,12 +156,12 @@ openssl req -new -x509 -days 3650 -sha256 \
-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"
convert_key_to_der "$CA_ALGO" "${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"
generate_private_key "$CA_ALGO" "${OUTPUT_DIR}/temp/intermediate.key.pem"
openssl req -new -sha256 \
-key ${OUTPUT_DIR}/temp/intermediate.key.pem \
@ -128,7 +169,7 @@ openssl req -new -sha256 \
-subj "$INTERMEDIATE_SUBJECT"
# Step 3: Sign Intermediate certificate with Root
openssl x509 -req -days 1825 -sha256 \
openssl x509 -req -days 1825 -$CA_HASH \
-in ${OUTPUT_DIR}/temp/intermediate.csr \
-out ${OUTPUT_DIR}/temp/intermediate.crt.pem \
-CA ${OUTPUT_DIR}/temp/root.crt.pem \
@ -137,19 +178,19 @@ openssl x509 -req -days 1825 -sha256 \
-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"
convert_key_to_der "$CA_ALGO" "${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"
generate_private_key "$LEAF_ALGO" "${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"
validate_key_format "$LEAF_ALGO" "${OUTPUT_DIR}/temp/leaf.key.pem"
fi
# Create CSR for leaf certificate
@ -158,8 +199,8 @@ openssl req -new -sha256 \
-out ${OUTPUT_DIR}/temp/leaf.csr \
-subj "$LEAF_SUBJECT"
# Step 5: Sign Leaf certificate with Intermediate
openssl x509 -req -days 365 -sha256 \
# Step 5: Sign Leaf certificate with Intermediate (CA key, CA hash)
openssl x509 -req -days 365 -$CA_HASH \
-in ${OUTPUT_DIR}/temp/leaf.csr \
-out ${OUTPUT_DIR}/temp/leaf.crt.pem \
-CA ${OUTPUT_DIR}/temp/intermediate.crt.pem \
@ -168,12 +209,12 @@ openssl x509 -req -days 365 -sha256 \
-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"
convert_key_to_der "$LEAF_ALGO" "${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"
extract_public_key "$LEAF_ALGO" "${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
@ -250,7 +291,7 @@ openssl verify -CAfile ${OUTPUT_DIR}/temp/root.crt.pem -untrusted ${OUTPUT_DIR}/
echo ""
echo "=== Generated Files Summary ==="
echo ""
echo "DER Format (Algorithm: $ALGO):"
echo "DER Format (CA: $CA_ALGO/$CA_HASH, leaf: $LEAF_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"