From c31df809d9171a3a23899eec063de7242a799b41 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:46:12 -0600 Subject: [PATCH 1/4] Add SW-only RSA PSS --- include/image.h | 10 ++++ include/loader.h | 9 ++-- include/user_settings.h | 26 +++++++-- include/wolfboot/wolfboot.h | 38 ++++++++++--- options.mk | 78 +++++++++++++++++++++++++++ src/image.c | 72 ++++++++++++++++++++++++- tools/keytools/keygen.c | 65 ++++++++++++++++------ tools/keytools/sign.c | 98 +++++++++++++++++++++++++++++++++- tools/keytools/user_settings.h | 1 + 9 files changed, 365 insertions(+), 32 deletions(-) diff --git a/include/image.h b/include/image.h index c9e7fcba10..38ea9f056b 100644 --- a/include/image.h +++ b/include/image.h @@ -68,6 +68,11 @@ extern "C" { defined (WOLFBOOT_SIGN_RSA4096ENC) #define wolfBoot_verify_signature_primary wolfBoot_verify_signature_rsa #endif +#if defined (WOLFBOOT_SIGN_RSAPSS2048) || \ + defined (WOLFBOOT_SIGN_RSAPSS3072) || \ + defined (WOLFBOOT_SIGN_RSAPSS4096) +#define wolfBoot_verify_signature_primary wolfBoot_verify_signature_rsa_pss +#endif #if defined (WOLFBOOT_SIGN_ECC256) || \ defined (WOLFBOOT_SIGN_ECC384) || \ defined (WOLFBOOT_SIGN_ECC521) @@ -97,6 +102,11 @@ extern "C" { defined (WOLFBOOT_SIGN_SECONDARY_RSA4096ENC) #define wolfBoot_verify_signature_secondary wolfBoot_verify_signature_rsa #endif +#if defined (WOLFBOOT_SIGN_SECONDARY_RSAPSS2048) || \ + defined (WOLFBOOT_SIGN_SECONDARY_RSAPSS3072) || \ + defined (WOLFBOOT_SIGN_SECONDARY_RSAPSS4096) +#define wolfBoot_verify_signature_secondary wolfBoot_verify_signature_rsa_pss +#endif #if defined (WOLFBOOT_SIGN_SECONDARY_ECC256) || \ defined (WOLFBOOT_SIGN_SECONDARY_ECC384) || \ defined (WOLFBOOT_SIGN_SECONDARY_ECC521) diff --git a/include/loader.h b/include/loader.h index 9d2ef37653..2e9f5a3e24 100644 --- a/include/loader.h +++ b/include/loader.h @@ -40,11 +40,14 @@ extern "C" { #define ECC_IMAGE_SIGNATURE_SIZE (132) #endif -#if defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) +#if defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) || \ + defined(WOLFBOOT_SIGN_RSAPSS2048) || defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS2048) #define RSA_IMAGE_SIGNATURE_SIZE (256) -#elif defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) +#elif defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) || \ + defined(WOLFBOOT_SIGN_RSAPSS3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS3072) #define RSA_IMAGE_SIGNATURE_SIZE (384) -#elif defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSA4096) +#elif defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSA4096) || \ + defined(WOLFBOOT_SIGN_RSAPSS4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS4096) #define RSA_IMAGE_SIGNATURE_SIZE (512) #endif diff --git a/include/user_settings.h b/include/user_settings.h index a513b9e93e..f59857e9a6 100644 --- a/include/user_settings.h +++ b/include/user_settings.h @@ -219,12 +219,25 @@ extern int tolower(int c); 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) || \ (defined(WOLFCRYPT_SECURE_MODE) && (!defined(PKCS11_SMALL))) # define WC_RSA_BLINDING # 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) +# define WC_RSA_PSS +# endif # if !defined(WOLFBOOT_TPM) && !defined(WOLFCRYPT_SECURE_MODE) && \ !defined(WOLFCRYPT_TEST) && !defined(WOLFCRYPT_BENCHMARK) && \ !defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \ @@ -232,7 +245,9 @@ extern int tolower(int c); # define WOLFSSL_RSA_VERIFY_INLINE # define WOLFSSL_RSA_VERIFY_ONLY # define WOLFSSL_RSA_PUBLIC_ONLY -# define WC_NO_RSA_OAEP +# if !defined(WC_RSA_PSS) +# define WC_NO_RSA_OAEP +# endif # define NO_RSA_BOUNDS_CHECK # endif # if !defined(USE_FAST_MATH) && !defined(WOLFSSL_SP_MATH_ALL) @@ -241,7 +256,8 @@ extern int tolower(int c); # define WOLFSSL_SP_SMALL # define WOLFSSL_SP_MATH # endif -# if defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) +# 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 @@ -250,7 +266,8 @@ extern int tolower(int c); # define RSA_MIN_SIZE 2048 # define RSA_MAX_SIZE 2048 # endif -# if defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) +# if defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) || \ + defined(WOLFBOOT_SIGN_RSAPSS3072) || defined(WOLFBOOT_SIGN_SECONDARY_RSAPSS3072) # define FP_MAX_BITS (3072 * 2) # define SP_INT_BITS 3072 # define WOLFSSL_SP_NO_2048 @@ -260,7 +277,8 @@ extern int tolower(int c); # define RSA_MAX_SIZE 3072 # endif -# if defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSA4096) +# 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 diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index af9d825b19..3a9f4053c5 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -112,16 +112,16 @@ extern "C" { #ifndef IMAGE_HEADER_SIZE /* Largest cases first */ -# if defined(WOLFBOOT_SIGN_RSA4096) +# if defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_RSAPSS4096) # define IMAGE_HEADER_SIZE 1024 - /* RSA3072 + strong hash */ -# elif (defined(WOLFBOOT_SIGN_RSA3072) && \ + /* RSA3072/RSAPSS3072 + strong hash */ +# elif ((defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_RSAPSS3072)) && \ (defined(WOLFBOOT_HASH_SHA384) || defined(WOLFBOOT_HASH_SHA3_384))) # define IMAGE_HEADER_SIZE 1024 - /* RSA2048 + SHA256 */ -# elif defined(WOLFBOOT_SIGN_RSA2048) && defined(WOLFBOOT_HASH_SHA256) + /* RSA2048/RSAPSS2048 + SHA256 */ +# elif (defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_RSAPSS2048)) && defined(WOLFBOOT_HASH_SHA256) # define IMAGE_HEADER_SIZE 512 /* ECC384 requires 512 with SHA256 */ @@ -141,7 +141,7 @@ extern "C" { # define IMAGE_HEADER_SIZE 256 /* Secondary 512-byte fallbacks */ -# elif defined(WOLFBOOT_SIGN_RSA3072) || \ +# elif defined(WOLFBOOT_SIGN_RSA3072) || defined(WOLFBOOT_SIGN_RSAPSS3072) || \ defined(WOLFBOOT_SIGN_ECC521) || \ defined(WOLFBOOT_SIGN_ED448) || \ defined(WOLFBOOT_HASH_SHA384) || \ @@ -224,7 +224,10 @@ extern "C" { #define AUTH_KEY_ECC521 0x07 #define AUTH_KEY_RSA3072 0x08 #define AUTH_KEY_LMS 0x09 - /* 0x0A...0x0F reserved */ +#define AUTH_KEY_RSAPSS2048 0x0A +#define AUTH_KEY_RSAPSS3072 0x0B +#define AUTH_KEY_RSAPSS4096 0x0C + /* 0x0D...0x0F reserved */ #define AUTH_KEY_XMSS 0x10 #define AUTH_KEY_ML_DSA 0x11 @@ -245,6 +248,9 @@ extern "C" { #define HDR_IMG_TYPE_AUTH_ECC521 (AUTH_KEY_ECC521 << 8) #define HDR_IMG_TYPE_AUTH_RSA3072 (AUTH_KEY_RSA3072 << 8) #define HDR_IMG_TYPE_AUTH_LMS (AUTH_KEY_LMS << 8) +#define HDR_IMG_TYPE_AUTH_RSAPSS2048 (AUTH_KEY_RSAPSS2048 << 8) +#define HDR_IMG_TYPE_AUTH_RSAPSS3072 (AUTH_KEY_RSAPSS3072 << 8) +#define HDR_IMG_TYPE_AUTH_RSAPSS4096 (AUTH_KEY_RSAPSS4096 << 8) #define HDR_IMG_TYPE_AUTH_XMSS (AUTH_KEY_XMSS << 8) #define HDR_IMG_TYPE_AUTH_ML_DSA (AUTH_KEY_ML_DSA << 8) @@ -265,6 +271,9 @@ extern "C" { #define KEYSTORE_PUBKEY_SIZE_RSA2048 320 #define KEYSTORE_PUBKEY_SIZE_RSA3072 448 #define KEYSTORE_PUBKEY_SIZE_RSA4096 576 +#define KEYSTORE_PUBKEY_SIZE_RSAPSS2048 KEYSTORE_PUBKEY_SIZE_RSA2048 +#define KEYSTORE_PUBKEY_SIZE_RSAPSS3072 KEYSTORE_PUBKEY_SIZE_RSA3072 +#define KEYSTORE_PUBKEY_SIZE_RSAPSS4096 KEYSTORE_PUBKEY_SIZE_RSA4096 #define KEYSTORE_PUBKEY_SIZE_LMS 60 #define KEYSTORE_PUBKEY_SIZE_XMSS 68 @@ -439,6 +448,21 @@ extern "C" { # ifndef WOLFBOOT_UNIVERSAL_KEYSTORE # define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA4096 # endif + #elif defined(WOLFBOOT_SIGN_RSAPSS2048) + # define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_RSAPSS2048 + # ifndef WOLFBOOT_UNIVERSAL_KEYSTORE + # define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA2048 + # endif + #elif defined(WOLFBOOT_SIGN_RSAPSS3072) + # define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_RSAPSS3072 + # ifndef WOLFBOOT_UNIVERSAL_KEYSTORE + # define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA3072 + # endif + #elif defined(WOLFBOOT_SIGN_RSAPSS4096) + # define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_RSAPSS4096 + # ifndef WOLFBOOT_UNIVERSAL_KEYSTORE + # define KEYSTORE_PUBKEY_SIZE KEYSTORE_PUBKEY_SIZE_RSA4096 + # endif #elif defined(WOLFBOOT_SIGN_LMS) # define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_LMS # ifndef WOLFBOOT_UNIVERSAL_KEYSTORE diff --git a/options.mk b/options.mk index 8e7d914fd7..9141bbad09 100644 --- a/options.mk +++ b/options.mk @@ -291,6 +291,84 @@ ifeq ($(SIGN),ED448) endif endif +ifeq ($(SIGN),RSAPSS2048) + KEYGEN_OPTIONS+=--rsapss2048 + SIGN_OPTIONS+=--rsapss2048 + SIGN_ALG=RSAPSS2048 + WOLFCRYPT_OBJS+= $(RSA_OBJS) + WOLFCRYPT_OBJS+=$(MATH_OBJS) + CFLAGS+=-D"WOLFBOOT_SIGN_RSAPSS2048" $(RSA_EXTRA_CFLAGS) + ifeq ($(WOLFBOOT_SMALL_STACK),1) + ifneq ($(SPMATH),1) + STACK_USAGE=5008 + else + STACK_USAGE=4096 + endif + else + ifneq ($(SPMATH),1) + STACK_USAGE=35952 + else + STACK_USAGE=17568 + endif + endif + ifeq ($(shell test $(IMAGE_HEADER_SIZE) -lt 512; echo $$?),0) + IMAGE_HEADER_SIZE=512 + endif +endif + +ifeq ($(SIGN),RSAPSS3072) + KEYGEN_OPTIONS+=--rsapss3072 + SIGN_OPTIONS+=--rsapss3072 + SIGN_ALG=RSAPSS3072 + WOLFCRYPT_OBJS+= $(RSA_OBJS) + WOLFCRYPT_OBJS+=$(MATH_OBJS) + CFLAGS+=-D"WOLFBOOT_SIGN_RSAPSS3072" $(RSA_EXTRA_CFLAGS) + ifeq ($(WOLFBOOT_SMALL_STACK),1) + ifneq ($(SPMATH),1) + STACK_USAGE=5008 + else + STACK_USAGE=4364 + endif + else + ifneq ($(SPMATH),1) + STACK_USAGE=52592 + else + STACK_USAGE=12288 + endif + endif + ifneq ($(HASH),SHA256) + IMAGE_HEADER_SIZE=1024 + endif + ifeq ($(shell test $(IMAGE_HEADER_SIZE) -lt 512; echo $$?),0) + IMAGE_HEADER_SIZE=512 + endif +endif + +ifeq ($(SIGN),RSAPSS4096) + KEYGEN_OPTIONS+=--rsapss4096 + SIGN_OPTIONS+=--rsapss4096 + SIGN_ALG=RSAPSS4096 + WOLFCRYPT_OBJS+= $(RSA_OBJS) + WOLFCRYPT_OBJS+=$(MATH_OBJS) + CFLAGS+=-D"WOLFBOOT_SIGN_RSAPSS4096" $(RSA_EXTRA_CFLAGS) + ifeq ($(WOLFBOOT_SMALL_STACK),1) + ifneq ($(SPMATH),1) + STACK_USAGE=5888 + else + STACK_USAGE=5768 + endif + else + ifneq ($(SPMATH),1) + STACK_USAGE=69232 + else + STACK_USAGE=18064 + endif + endif + ifeq ($(shell test $(IMAGE_HEADER_SIZE) -lt 1024; echo $$?),0) + IMAGE_HEADER_SIZE=1024 + endif +endif + ifneq ($(findstring RSA2048,$(SIGN)),) KEYGEN_OPTIONS+=--rsa2048 ifeq ($(SIGN),RSA2048ENC) diff --git a/src/image.c b/src/image.c index 6d87db1616..904cb10c6c 100644 --- a/src/image.c +++ b/src/image.c @@ -364,7 +364,13 @@ static void wolfBoot_verify_signature_ecc(uint8_t key_slot, defined(WOLFBOOT_SIGN_RSA4096) || \ defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) || \ defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) || \ - defined(WOLFBOOT_SIGN_SECONDARY_RSA4096) + 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) #include #include @@ -562,6 +568,65 @@ static void wolfBoot_verify_signature_rsa(uint8_t key_slot, * WOLFBOOT_SIGN_RSA4096 || WOLFBOOT_SIGN_SECONDARY_RSA2048 || * WOLFBOOT_SIGN_SECONDARY_RSA3072 || WOLFBOOT_SIGN_SECONDARY_RSA4096 */ +#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) + +static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, + struct wolfBoot_image *img, uint8_t *sig) +{ + int ret; + uint8_t output[RSA_IMAGE_SIGNATURE_SIZE]; + uint8_t* digest_out = NULL; + word32 inOutIdx = 0; + struct RsaKey rsa; + +#if defined(WOLFBOOT_HASH_SHA256) + enum wc_HashType hash_type = WC_HASH_TYPE_SHA256; + int mgf = WC_MGF1SHA256; +#elif defined(WOLFBOOT_HASH_SHA384) + enum wc_HashType hash_type = WC_HASH_TYPE_SHA384; + int mgf = WC_MGF1SHA384; +#else + #error "RSA-PSS requires SHA-256 or SHA-384" +#endif + + uint8_t *pubkey = keystore_get_buffer(key_slot); + int pubkey_sz = keystore_get_size(key_slot); + + if (pubkey == NULL || pubkey_sz < 0) { + return; + } + + /* wolfCrypt software RSA-PSS verify */ + ret = wc_InitRsaKey(&rsa, NULL); + if (ret == 0) { + /* Import public key */ + ret = wc_RsaPublicKeyDecode((byte*)pubkey, &inOutIdx, &rsa, pubkey_sz); + if (ret >= 0) { + XMEMCPY(output, sig, RSA_IMAGE_SIGNATURE_SIZE); + RSA_VERIFY_FN(ret, + wc_RsaPSS_VerifyCheckInline, output, RSA_IMAGE_SIGNATURE_SIZE, + &digest_out, img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, + hash_type, mgf, &rsa); + } + } + wc_FreeRsaKey(&rsa); + /* wc_RsaPSS_VerifyCheckInline returns the PSS-verified data length on + * success (>= digest size), or a negative error code on failure. + * The hash comparison is performed internally by the function. */ + if (ret >= WOLFBOOT_SHA_DIGEST_SIZE && img) { + wolfBoot_image_confirm_signature_ok(img); + } +} + +#endif /* WOLFBOOT_SIGN_RSAPSS2048 || WOLFBOOT_SIGN_RSAPSS3072 || \ + * WOLFBOOT_SIGN_RSAPSS4096 || WOLFBOOT_SIGN_SECONDARY_RSAPSS2048 || \ + * WOLFBOOT_SIGN_SECONDARY_RSAPSS3072 || WOLFBOOT_SIGN_SECONDARY_RSAPSS4096 */ + #ifdef WOLFBOOT_SIGN_LMS #include #ifdef HAVE_LIBLMS @@ -2271,7 +2336,10 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img) defined (WOLFBOOT_SIGN_RSA4096) || \ defined (WOLFBOOT_SIGN_RSA2048ENC) || \ defined (WOLFBOOT_SIGN_RSA3072ENC) || \ - defined (WOLFBOOT_SIGN_RSA4096ENC) + defined (WOLFBOOT_SIGN_RSA4096ENC) || \ + defined (WOLFBOOT_SIGN_RSAPSS2048) || \ + defined (WOLFBOOT_SIGN_RSAPSS3072) || \ + defined (WOLFBOOT_SIGN_RSAPSS4096) if (stored_signature_size != RSA_IMAGE_SIGNATURE_SIZE) return -1; #elif defined (WOLFBOOT_SIGN_ECC256) || \ diff --git a/tools/keytools/keygen.c b/tools/keytools/keygen.c index 97f38340d6..4960352677 100644 --- a/tools/keytools/keygen.c +++ b/tools/keytools/keygen.c @@ -108,6 +108,9 @@ #define KEYGEN_LMS 9 #define KEYGEN_XMSS 10 #define KEYGEN_ML_DSA 11 +#define KEYGEN_RSAPSS2048 12 +#define KEYGEN_RSAPSS3072 13 +#define KEYGEN_RSAPSS4096 14 /* Globals */ static FILE *fpub, *fpub_image; @@ -296,7 +299,7 @@ static void fwritekey(uint8_t *key, int len, FILE *f) } } -const char KType[][17] = { +const char KType[][21] = { "AUTH_KEY_NONE", "AUTH_KEY_ED25519", "AUTH_KEY_ECC256", @@ -308,7 +311,10 @@ const char KType[][17] = { "AUTH_KEY_RSA3072", "AUTH_KEY_LMS", "AUTH_KEY_XMSS", - "AUTH_KEY_ML_DSA" + "AUTH_KEY_ML_DSA", + "AUTH_KEY_RSAPSS2048", + "AUTH_KEY_RSAPSS3072", + "AUTH_KEY_RSAPSS4096" }; const char KSize[][29] = { @@ -323,10 +329,13 @@ const char KSize[][29] = { "KEYSTORE_PUBKEY_SIZE_RSA3072", "KEYSTORE_PUBKEY_SIZE_LMS", "KEYSTORE_PUBKEY_SIZE_XMSS", - "KEYSTORE_PUBKEY_SIZE_ML_DSA" + "KEYSTORE_PUBKEY_SIZE_ML_DSA", + "KEYSTORE_PUBKEY_SIZE_RSA2048", + "KEYSTORE_PUBKEY_SIZE_RSA3072", + "KEYSTORE_PUBKEY_SIZE_RSA4096" }; -const char KName[][8] = { +const char KName[][12] = { "NONE", "ED25519", "ECC256", @@ -338,7 +347,10 @@ const char KName[][8] = { "RSA3072", "LMS", "XMSS", - "ML_DSA" + "ML_DSA", + "RSAPSS2048", + "RSAPSS3072", + "RSAPSS4096" }; #define MAX_PUBKEYS 64 @@ -446,6 +458,15 @@ static uint32_t get_pubkey_size(uint32_t keyType) case KEYGEN_RSA4096: size = KEYSTORE_PUBKEY_SIZE_RSA4096; break; + case KEYGEN_RSAPSS2048: + size = KEYSTORE_PUBKEY_SIZE_RSA2048; + break; + case KEYGEN_RSAPSS3072: + size = KEYSTORE_PUBKEY_SIZE_RSA3072; + break; + case KEYGEN_RSAPSS4096: + size = KEYSTORE_PUBKEY_SIZE_RSA4096; + break; case KEYGEN_LMS: size = KEYSTORE_PUBKEY_SIZE_LMS; break; @@ -541,7 +562,8 @@ void keystore_add(uint32_t ktype, uint8_t *key, uint32_t sz, const char *keyfile } -static void keygen_rsa(const char *keyfile, int kbits, uint32_t id_mask) +static void keygen_rsa(const char *keyfile, int kbits, uint32_t id_mask, + int ktype) { RsaKey k; uint8_t priv_der[4096], pub_der[2048]; @@ -583,12 +605,7 @@ static void keygen_rsa(const char *keyfile, int kbits, uint32_t id_mask) } } - if (kbits == 2048) - keystore_add(KEYGEN_RSA2048, pub_der, publen, keyfile, id_mask); - else if (kbits == 3072) - keystore_add(KEYGEN_RSA3072, pub_der, publen, keyfile, id_mask); - else if (kbits == 4096) - keystore_add(KEYGEN_RSA4096, pub_der, publen, keyfile, id_mask); + keystore_add(ktype, pub_der, publen, keyfile, id_mask); } #define MAX_ECC_KEY_SIZE 66 @@ -1210,13 +1227,22 @@ static void key_generate(uint32_t ktype, const char *kfilename, uint32_t id_mask #ifndef NO_RSA case KEYGEN_RSA2048: - keygen_rsa(kfilename, 2048, id_mask); + keygen_rsa(kfilename, 2048, id_mask, KEYGEN_RSA2048); break; case KEYGEN_RSA3072: - keygen_rsa(kfilename, 3072, id_mask); + keygen_rsa(kfilename, 3072, id_mask, KEYGEN_RSA3072); break; case KEYGEN_RSA4096: - keygen_rsa(kfilename, 4096, id_mask); + keygen_rsa(kfilename, 4096, id_mask, KEYGEN_RSA4096); + break; + case KEYGEN_RSAPSS2048: + keygen_rsa(kfilename, 2048, id_mask, KEYGEN_RSAPSS2048); + break; + case KEYGEN_RSAPSS3072: + keygen_rsa(kfilename, 3072, id_mask, KEYGEN_RSAPSS3072); + break; + case KEYGEN_RSAPSS4096: + keygen_rsa(kfilename, 4096, id_mask, KEYGEN_RSAPSS4096); break; #endif @@ -1391,6 +1417,15 @@ int main(int argc, char** argv) else if (strcmp(argv[i], "--rsa4096") == 0) { keytype = KEYGEN_RSA4096; } + else if (strcmp(argv[i], "--rsapss2048") == 0) { + keytype = KEYGEN_RSAPSS2048; + } + else if (strcmp(argv[i], "--rsapss3072") == 0) { + keytype = KEYGEN_RSAPSS3072; + } + else if (strcmp(argv[i], "--rsapss4096") == 0) { + keytype = KEYGEN_RSAPSS4096; + } #if defined(WOLFSSL_HAVE_LMS) else if (strcmp(argv[i], "--lms") == 0) { keytype = KEYGEN_LMS; diff --git a/tools/keytools/sign.c b/tools/keytools/sign.c index b0d4778a07..40cdd1f536 100644 --- a/tools/keytools/sign.c +++ b/tools/keytools/sign.c @@ -193,6 +193,9 @@ static inline int fp_truncate(FILE *f, size_t len) #define SIGN_RSA2048 HDR_IMG_TYPE_AUTH_RSA2048 #define SIGN_RSA3072 HDR_IMG_TYPE_AUTH_RSA3072 #define SIGN_RSA4096 HDR_IMG_TYPE_AUTH_RSA4096 +#define SIGN_RSAPSS2048 HDR_IMG_TYPE_AUTH_RSAPSS2048 +#define SIGN_RSAPSS3072 HDR_IMG_TYPE_AUTH_RSAPSS3072 +#define SIGN_RSAPSS4096 HDR_IMG_TYPE_AUTH_RSAPSS4096 #define SIGN_ED448 HDR_IMG_TYPE_AUTH_ED448 #define SIGN_ECC384 HDR_IMG_TYPE_AUTH_ECC384 #define SIGN_ECC521 HDR_IMG_TYPE_AUTH_ECC521 @@ -756,6 +759,25 @@ static uint8_t *load_key(uint8_t **key_buffer, uint32_t *key_buffer_sz, if (ret == 0) break; + FALL_THROUGH; /* we didn't solve the key, keep trying */ + case SIGN_RSAPSS2048: + ret = load_key_rsa(SIGN_RSAPSS2048, 256, KEYSTORE_PUBKEY_SIZE_RSA2048, 512, + key_buffer, key_buffer_sz, pubkey, pubkey_sz, secondary); + if (ret == 0) + break; + FALL_THROUGH; + case SIGN_RSAPSS3072: + ret = load_key_rsa(SIGN_RSAPSS3072, 384, KEYSTORE_PUBKEY_SIZE_RSA3072, 512, + key_buffer, key_buffer_sz, pubkey, pubkey_sz, secondary); + if (ret == 0) + break; + FALL_THROUGH; + case SIGN_RSAPSS4096: + ret = load_key_rsa(SIGN_RSAPSS4096, 512, KEYSTORE_PUBKEY_SIZE_RSA4096, 1024, + key_buffer, key_buffer_sz, pubkey, pubkey_sz, secondary); + if (ret == 0) + break; + FALL_THROUGH; /* we didn't solve the key, keep trying */ case SIGN_LMS: ret = -1; @@ -1029,6 +1051,30 @@ static int sign_digest(int sign, int hash_algo, } } else + if (sign == SIGN_RSAPSS2048 || + sign == SIGN_RSAPSS3072 || + sign == SIGN_RSAPSS4096) + { + enum wc_HashType hash_type; + int mgf; + if (hash_algo == HASH_SHA256) { + hash_type = WC_HASH_TYPE_SHA256; + mgf = WC_MGF1SHA256; + } else if (hash_algo == HASH_SHA384) { + hash_type = WC_HASH_TYPE_SHA384; + mgf = WC_MGF1SHA384; + } else { + fprintf(stderr, "RSA-PSS requires SHA-256 or SHA-384\n"); + return -1; + } + ret = wc_RsaPSS_Sign(digest, digest_sz, signature, *signature_sz, + hash_type, mgf, &key.rsa, &rng); + if (ret > 0) { + *signature_sz = ret; + ret = 0; + } + } + else if (sign == SIGN_LMS) { const char *key_file = CMD.key_file; if (secondary) { @@ -2341,6 +2387,23 @@ static void set_signature_sizes(int secondary) CMD.header_sz = 1024; *sz = 512; } + else if (*sign == SIGN_RSAPSS2048) { + if (CMD.header_sz < 512) + CMD.header_sz = 512; + *sz = 256; + } + else if (*sign == SIGN_RSAPSS3072) { + if ((CMD.header_sz < 1024) && (CMD.hash_algo != HASH_SHA256)) + CMD.header_sz = 1024; + if (CMD.header_sz < 512) + CMD.header_sz = 512; + *sz = 384; + } + else if (*sign == SIGN_RSAPSS4096) { + if (CMD.header_sz < 1024) + CMD.header_sz = 1024; + *sz = 512; + } else if (*sign == SIGN_LMS) { int lms_ret = 0; word32 sig_sz = 0; @@ -2634,6 +2697,36 @@ int main(int argc, char** argv) sign_str = "RSA4096"; } } + else if (strcmp(argv[i], "--rsapss2048") == 0) { + if (CMD.sign != SIGN_AUTO) { + CMD.hybrid = 1; + CMD.secondary_sign = SIGN_RSAPSS2048; + secondary_sign_str = "RSAPSS2048"; + } else { + CMD.sign = SIGN_RSAPSS2048; + sign_str = "RSAPSS2048"; + } + } + else if (strcmp(argv[i], "--rsapss3072") == 0) { + if (CMD.sign != SIGN_AUTO) { + CMD.hybrid = 1; + CMD.secondary_sign = SIGN_RSAPSS3072; + secondary_sign_str = "RSAPSS3072"; + } else { + CMD.sign = SIGN_RSAPSS3072; + sign_str = "RSAPSS3072"; + } + } + else if (strcmp(argv[i], "--rsapss4096") == 0) { + if (CMD.sign != SIGN_AUTO) { + CMD.hybrid = 1; + CMD.secondary_sign = SIGN_RSAPSS4096; + secondary_sign_str = "RSAPSS4096"; + } else { + CMD.sign = SIGN_RSAPSS4096; + sign_str = "RSAPSS4096"; + } + } else if (strcmp(argv[i], "--lms") == 0) { if (CMD.sign != SIGN_AUTO) { CMD.hybrid = 1; @@ -3042,7 +3135,10 @@ int main(int argc, char** argv) } else if (CMD.sign == SIGN_RSA2048 || CMD.sign == SIGN_RSA3072 || - CMD.sign == SIGN_RSA4096) { + CMD.sign == SIGN_RSA4096 || + CMD.sign == SIGN_RSAPSS2048 || + CMD.sign == SIGN_RSAPSS3072 || + CMD.sign == SIGN_RSAPSS4096) { wc_FreeRsaKey(&key.rsa); } else if (CMD.sign == SIGN_LMS) { diff --git a/tools/keytools/user_settings.h b/tools/keytools/user_settings.h index 7c888d115c..cb7d8a3d8d 100644 --- a/tools/keytools/user_settings.h +++ b/tools/keytools/user_settings.h @@ -68,6 +68,7 @@ /* RSA */ #define HAVE_RSA #define WC_RSA_BLINDING +#define WC_RSA_PSS #define WOLFSSL_KEY_GEN /* Hashing */ From 8af2bf62e72b6017d60e8b1c64bb774ca22c6453 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:57:07 -0600 Subject: [PATCH 2/4] expand tests, add additional macro protection, fix keygen type bug --- .github/workflows/test-sunnyday-simulator.yml | 240 ++++++++++++++++++ config/examples/sim-rsapss2048.config | 21 ++ options.mk | 12 + src/image.c | 16 +- tools/keytools/keygen.c | 11 +- 5 files changed, 297 insertions(+), 3 deletions(-) create mode 100644 config/examples/sim-rsapss2048.config diff --git a/.github/workflows/test-sunnyday-simulator.yml b/.github/workflows/test-sunnyday-simulator.yml index b537b51e14..507f8600e1 100644 --- a/.github/workflows/test-sunnyday-simulator.yml +++ b/.github/workflows/test-sunnyday-simulator.yml @@ -218,6 +218,66 @@ jobs: run: | tools/scripts/sim-sunnyday-update.sh + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS2048) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS2048, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 WOLFBOOT_SMALL_STACK=1 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS3072) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS3072, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 WOLFBOOT_SMALL_STACK=1 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS4096) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS4096, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 WOLFBOOT_SMALL_STACK=1 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + # 32 Bit simulator, FASTMATH # - name: make clean @@ -348,6 +408,66 @@ jobs: run: | tools/scripts/sim-sunnyday-update.sh + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS2048, FASTMATH) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS2048, FASTMATH, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 WOLFBOOT_SMALL_STACK=1 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS3072, FASTMATH) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS3072, FASTMATH, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 WOLFBOOT_SMALL_STACK=1 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS4096, FASTMATH) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 SPMATH=0 WOLFBOOT_HUGE_STACK=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS4096, FASTMATH, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 WOLFBOOT_SMALL_STACK=1 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + # 64 Bit simulator, SP_MATH # @@ -479,6 +599,66 @@ jobs: run: | tools/scripts/sim-sunnyday-update.sh + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS2048) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS2048, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 WOLFBOOT_SMALL_STACK=1 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS3072) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS3072, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 WOLFBOOT_SMALL_STACK=1 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS4096) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS4096, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 WOLFBOOT_SMALL_STACK=1 SPMATH=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + # 64 Bit simulator, FASTMATH # - name: make clean @@ -609,6 +789,66 @@ jobs: run: | tools/scripts/sim-sunnyday-update.sh + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS2048, FASTMATH) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS2048, FASTMATH, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS2048 WOLFBOOT_SMALL_STACK=1 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS3072, FASTMATH) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS3072, FASTMATH, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS3072 WOLFBOOT_SMALL_STACK=1 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Cleanup to change key type + run: | + make keysclean + + - name: Build wolfboot.elf (RSAPSS4096, FASTMATH) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 SPMATH=0 WOLFBOOT_HUGE_STACK=1 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (RSAPSS4096, FASTMATH, WOLFBOOT_SMALL_STACK) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=RSAPSS4096 WOLFBOOT_SMALL_STACK=1 SPMATH=0 + + - name: Run sunny day update test + run: | + tools/scripts/sim-sunnyday-update.sh + - name: Run sunny day LMS update test run: | tools/scripts/sim-pq-sunnyday-update.sh config/examples/sim-lms.config diff --git a/config/examples/sim-rsapss2048.config b/config/examples/sim-rsapss2048.config new file mode 100644 index 0000000000..8effe6e57c --- /dev/null +++ b/config/examples/sim-rsapss2048.config @@ -0,0 +1,21 @@ +ARCH=sim +TARGET=sim +SIGN?=RSAPSS2048 +HASH?=SHA256 +WOLFBOOT_SMALL_STACK?=0 +SPI_FLASH=0 +DEBUG=1 + +# sizes should be multiple of system page size +WOLFBOOT_PARTITION_SIZE=0x40000 +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 + +# required for keytools +WOLFBOOT_FIXED_PARTITIONS=1 + +# For debugging XMALLOC/XFREE +#CFLAGS_EXTRA+=-DWOLFBOOT_DEBUG_MALLOC diff --git a/options.mk b/options.mk index 9141bbad09..99c1494e77 100644 --- a/options.mk +++ b/options.mk @@ -574,6 +574,18 @@ ifneq ($(SIGN_SECONDARY),) WOLFCRYPT_OBJS+=$(RSA_OBJS) WOLFCRYPT_OBJS+=$(MATH_OBJS) endif + ifeq ($(SIGN_SECONDARY),RSAPSS2048) + WOLFCRYPT_OBJS+=$(RSA_OBJS) + WOLFCRYPT_OBJS+=$(MATH_OBJS) + endif + ifeq ($(SIGN_SECONDARY),RSAPSS3072) + WOLFCRYPT_OBJS+=$(RSA_OBJS) + WOLFCRYPT_OBJS+=$(MATH_OBJS) + endif + ifeq ($(SIGN_SECONDARY),RSAPSS4096) + WOLFCRYPT_OBJS+=$(RSA_OBJS) + WOLFCRYPT_OBJS+=$(MATH_OBJS) + endif ifeq ($(SIGN_SECONDARY),ECC256) WOLFCRYPT_OBJS+=$(ECC_OBJS) WOLFCRYPT_OBJS+=$(MATH_OBJS) diff --git a/src/image.c b/src/image.c index 904cb10c6c..ca95f15132 100644 --- a/src/image.c +++ b/src/image.c @@ -617,7 +617,16 @@ static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, wc_FreeRsaKey(&rsa); /* wc_RsaPSS_VerifyCheckInline returns the PSS-verified data length on * success (>= digest size), or a negative error code on failure. - * The hash comparison is performed internally by the function. */ + * The hash comparison is performed internally by the function. + * + * Note: uses '>=' rather than '==' because PSS verify returns the digest + * size on success, unlike PKCS#1 v1.5 which returns exact decoded length. + * + * ARMORED limitation: the PKCS#1 v1.5 path uses both RSA_VERIFY_FN and + * RSA_VERIFY_HASH armored macros (two hardened gates), but PSS only uses + * RSA_VERIFY_FN because wc_RsaPSS_VerifyCheckInline performs the hash + * comparison internally. The branch below is not armored. Full armored + * hardening for PSS would require a new macro or restructuring. */ if (ret >= WOLFBOOT_SHA_DIGEST_SIZE && img) { wolfBoot_image_confirm_signature_ok(img); } @@ -2411,7 +2420,10 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img) defined (WOLFBOOT_SIGN_SECONDARY_RSA4096) || \ defined (WOLFBOOT_SIGN_SECONDARY_RSA2048ENC) || \ defined (WOLFBOOT_SIGN_SECONDARY_RSA3072ENC) || \ - defined (WOLFBOOT_SIGN_SECONDARY_RSA4096ENC) + defined (WOLFBOOT_SIGN_SECONDARY_RSA4096ENC) || \ + defined (WOLFBOOT_SIGN_SECONDARY_RSAPSS2048) || \ + defined (WOLFBOOT_SIGN_SECONDARY_RSAPSS3072) || \ + defined (WOLFBOOT_SIGN_SECONDARY_RSAPSS4096) expected_secondary_signature_size = RSA_IMAGE_SIGNATURE_SIZE; #elif defined (WOLFBOOT_SIGN_SECONDARY_ECC256) || \ defined (WOLFBOOT_SIGN_SECONDARY_ECC384) || \ diff --git a/tools/keytools/keygen.c b/tools/keytools/keygen.c index 4960352677..9d7e32a764 100644 --- a/tools/keytools/keygen.c +++ b/tools/keytools/keygen.c @@ -535,7 +535,16 @@ void keystore_add(uint32_t ktype, uint8_t *key, uint32_t sz, const char *keyfile memset(&sl, 0, sizeof(sl)); sl.slot_id = id_slot; - sl.key_type = ktype; + /* Map keygen key type to AUTH_KEY_* value for binary keystore. + * KEYGEN_RSAPSS* values (12-14) differ from AUTH_KEY_RSAPSS* (0x0A-0x0C). */ + if (ktype == KEYGEN_RSAPSS2048) + sl.key_type = AUTH_KEY_RSAPSS2048; + else if (ktype == KEYGEN_RSAPSS3072) + sl.key_type = AUTH_KEY_RSAPSS3072; + else if (ktype == KEYGEN_RSAPSS4096) + sl.key_type = AUTH_KEY_RSAPSS4096; + else + sl.key_type = ktype; sl.part_id_mask = id_mask; sl.pubkey_size = get_pubkey_size(ktype); From 03e3afc247d7f8f9ba2fc23aeb3e48a8ff9df7c7 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:57:44 -0600 Subject: [PATCH 3/4] support rsa-pss in ARMORED mode --- include/image.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++++ src/image.c | 31 ++++++++++------------- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/include/image.h b/include/image.h index 38ea9f056b..c2a14a79fe 100644 --- a/include/image.h +++ b/include/image.h @@ -478,6 +478,67 @@ static void __attribute__((noinline)) wolfBoot_image_clear_signature_ok( asm volatile("nop"); \ } +/** + * Second part of RSA-PSS verification. + * + * Call wc_RsaPSS_CheckPadding twice, then confirm via + * wolfBoot_image_confirm_signature_ok(); + */ +#define RSA_PSS_VERIFY_HASH(img, pss_data, pss_data_sz, hash_type) \ + { \ + volatile int pss_res; \ + if (!img || !pss_data) \ + asm volatile("b pnope"); \ + /* Redundant set of r0=50*/ \ + asm volatile("mov r0, #50":::"r0"); \ + asm volatile("mov r0, #50":::"r0"); \ + asm volatile("mov r0, #50":::"r0"); \ + pss_res = wc_RsaPSS_CheckPadding(img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, \ + pss_data, pss_data_sz, hash_type); \ + /* Redundant checks that ensure the function actually returned 0 */ \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("bne pnope":::"cc"); \ + asm volatile("cmp r0, #0"); \ + asm volatile("cmp r0, #0"); \ + asm volatile("cmp r0, #0"); \ + asm volatile("bne pnope":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("bne pnope"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("bne pnope"); \ + /* Repeat wc_RsaPSS_CheckPadding call */ \ + pss_res = wc_RsaPSS_CheckPadding(img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, \ + pss_data, pss_data_sz, hash_type); \ + pss_res; \ + /* Redundant checks that ensure the function actually returned 0 */ \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("bne pnope"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("bne pnope"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("bne pnope"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("cmp r0, #0":::"cc"); \ + asm volatile("bne pnope"); \ + /* Confirm that the signature is OK */ \ + wolfBoot_image_confirm_signature_ok(img); \ + asm volatile("pnope:"); \ + asm volatile("nop"); \ + } + /** * ECC / Ed / PQ signature verification. * Those verify functions set an additional value 'p_res' @@ -1247,6 +1308,11 @@ static void UNUSEDFUNCTION wolfBoot_image_clear_signature_ok( if (XMEMCMP(img->sha_hash, digest, WOLFBOOT_SHA_DIGEST_SIZE) == 0) \ wolfBoot_image_confirm_signature_ok(img); +#define RSA_PSS_VERIFY_HASH(img, pss_data, pss_data_sz, hash_type) \ + if (wc_RsaPSS_CheckPadding(img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, \ + pss_data, pss_data_sz, hash_type) == 0) \ + wolfBoot_image_confirm_signature_ok(img); + #define PART_SANITY_CHECK(p) \ if (((p)->hdr_ok != 1) || ((p)->sha_ok != 1) || ((p)->signature_ok != 1)) \ wolfBoot_panic() diff --git a/src/image.c b/src/image.c index ca95f15132..548ab35fe9 100644 --- a/src/image.c +++ b/src/image.c @@ -601,7 +601,15 @@ static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, return; } - /* wolfCrypt software RSA-PSS verify */ + /* wolfCrypt software RSA-PSS verify (two-step) + * + * Step 1 (RSA_VERIFY_FN): wc_RsaPSS_VerifyInline performs the RSA + * operation and PSS unmasking, returning a pointer to the PSS data and + * its length. + * + * Step 2 (RSA_PSS_VERIFY_HASH): wc_RsaPSS_CheckPadding verifies the PSS + * padding against img->sha_hash. Returns 0 on success. Both steps are + * armored when WOLFBOOT_ARMORED is enabled. */ ret = wc_InitRsaKey(&rsa, NULL); if (ret == 0) { /* Import public key */ @@ -609,26 +617,13 @@ static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, if (ret >= 0) { XMEMCPY(output, sig, RSA_IMAGE_SIGNATURE_SIZE); RSA_VERIFY_FN(ret, - wc_RsaPSS_VerifyCheckInline, output, RSA_IMAGE_SIGNATURE_SIZE, - &digest_out, img->sha_hash, WOLFBOOT_SHA_DIGEST_SIZE, - hash_type, mgf, &rsa); + wc_RsaPSS_VerifyInline, output, RSA_IMAGE_SIGNATURE_SIZE, + &digest_out, hash_type, mgf, &rsa); } } wc_FreeRsaKey(&rsa); - /* wc_RsaPSS_VerifyCheckInline returns the PSS-verified data length on - * success (>= digest size), or a negative error code on failure. - * The hash comparison is performed internally by the function. - * - * Note: uses '>=' rather than '==' because PSS verify returns the digest - * size on success, unlike PKCS#1 v1.5 which returns exact decoded length. - * - * ARMORED limitation: the PKCS#1 v1.5 path uses both RSA_VERIFY_FN and - * RSA_VERIFY_HASH armored macros (two hardened gates), but PSS only uses - * RSA_VERIFY_FN because wc_RsaPSS_VerifyCheckInline performs the hash - * comparison internally. The branch below is not armored. Full armored - * hardening for PSS would require a new macro or restructuring. */ - if (ret >= WOLFBOOT_SHA_DIGEST_SIZE && img) { - wolfBoot_image_confirm_signature_ok(img); + if (ret >= WOLFBOOT_SHA_DIGEST_SIZE && img && digest_out) { + RSA_PSS_VERIFY_HASH(img, digest_out, ret, hash_type); } } From 2932b9f2a921529cf71b407bf01a6dd08941d049 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Mon, 23 Mar 2026 12:49:26 -0600 Subject: [PATCH 4/4] add wolfHSM support --- src/image.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/image.c b/src/image.c index 548ab35fe9..437fede19c 100644 --- a/src/image.c +++ b/src/image.c @@ -584,6 +584,8 @@ static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, word32 inOutIdx = 0; struct RsaKey rsa; + (void)inOutIdx; + #if defined(WOLFBOOT_HASH_SHA256) enum wc_HashType hash_type = WC_HASH_TYPE_SHA256; int mgf = WC_MGF1SHA256; @@ -594,14 +596,19 @@ static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, #error "RSA-PSS requires SHA-256 or SHA-384" #endif +#if (!defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \ + !defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER)) || \ + (defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \ + !defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID)) uint8_t *pubkey = keystore_get_buffer(key_slot); int pubkey_sz = keystore_get_size(key_slot); if (pubkey == NULL || pubkey_sz < 0) { return; } +#endif - /* wolfCrypt software RSA-PSS verify (two-step) + /* RSA-PSS verify (two-step) * * Step 1 (RSA_VERIFY_FN): wc_RsaPSS_VerifyInline performs the RSA * operation and PSS unmasking, returning a pointer to the PSS data and @@ -610,6 +617,78 @@ static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, * Step 2 (RSA_PSS_VERIFY_HASH): wc_RsaPSS_CheckPadding verifies the PSS * padding against img->sha_hash. Returns 0 on success. Both steps are * armored when WOLFBOOT_ARMORED is enabled. */ +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) || \ + defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) + ret = wc_InitRsaKey_ex(&rsa, NULL, hsmDevIdPubKey); + if (ret != 0) { + return; + } +#if defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID) || \ + (defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) && \ + defined(WOLFBOOT_CERT_CHAIN_VERIFY)) + (void)key_slot; + /* public key is stored on server at hsmKeyIdPubKey*/ +#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 */ +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) + ret = wh_Client_RsaSetKeyId(&rsa, g_certLeafKeyId); +#elif defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) + ret = wh_Server_CacheExportRsaKey(&hsmServerCtx, g_certLeafKeyId, &rsa); +#endif + wolfBoot_printf( + "Using leaf cert public key (ID: %08x) for RSA-PSS verification\n", + (unsigned int)g_certLeafKeyId); + } + else { +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) + /* Default behavior: use the pre-configured public key ID */ + ret = wh_Client_RsaSetKeyId(&rsa, hsmKeyIdPubKey); +#endif + } +#else + ret = wh_Client_RsaSetKeyId(&rsa, hsmKeyIdPubKey); +#endif + if (ret != 0) { + return; + } +#else + whKeyId hsmKeyId = WH_KEYID_ERASED; + /* Cache the public key on the server */ + ret = wh_Client_KeyCache(&hsmClientCtx, WH_NVM_FLAGS_USAGE_VERIFY, NULL, 0, + pubkey, pubkey_sz, &hsmKeyId); + if (ret != WH_ERROR_OK) { + return; + } + /* Associate this RSA struct with the keyId of the cached key */ + ret = wh_Client_RsaSetKeyId(&rsa, hsmKeyId); + if (ret != WH_ERROR_OK) { + return; + } +#endif /* !WOLFBOOT_USE_WOLFHSM_PUBKEY_ID */ + XMEMCPY(output, sig, RSA_IMAGE_SIGNATURE_SIZE); + RSA_VERIFY_FN(ret, wc_RsaPSS_VerifyInline, output, RSA_IMAGE_SIGNATURE_SIZE, + &digest_out, hash_type, mgf, &rsa); +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) && \ + !defined(WOLFBOOT_USE_WOLFHSM_PUBKEY_ID) + /* evict the key after use, since we aren't using the RSA import API */ + if (WH_ERROR_OK != wh_Client_KeyEvict(&hsmClientCtx, hsmKeyId)) { + return; + } +#elif defined(WOLFBOOT_CERT_CHAIN_VERIFY) + if (g_leafKeyIdValid) { +#if defined(WOLFBOOT_ENABLE_WOLFHSM_CLIENT) + (void)wh_Client_KeyEvict(&hsmClientCtx, g_certLeafKeyId); +#elif defined(WOLFBOOT_ENABLE_WOLFHSM_SERVER) + (void)wh_Server_KeystoreEvictKey(&hsmServerCtx, g_certLeafKeyId); +#endif + g_leafKeyIdValid = 0; + } +#endif /* !WOLFBOOT_USE_WOLFHSM_PUBKEY_ID */ +#else + /* wolfCrypt software RSA-PSS verify */ ret = wc_InitRsaKey(&rsa, NULL); if (ret == 0) { /* Import public key */ @@ -621,6 +700,7 @@ static void wolfBoot_verify_signature_rsa_pss(uint8_t key_slot, &digest_out, hash_type, mgf, &rsa); } } +#endif /* WOLFBOOT_ENABLE_WOLFHSM */ wc_FreeRsaKey(&rsa); if (ret >= WOLFBOOT_SHA_DIGEST_SIZE && img && digest_out) { RSA_PSS_VERIFY_HASH(img, digest_out, ret, hash_type);