From c2bedd3ef7745ac36041cb913459a5119ad689b0 Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Tue, 30 Jun 2026 09:37:55 +0200 Subject: [PATCH] se050: implement dynamic hw/sw offload --- .github/workflows/se050-sim.yml | 28 +- wolfcrypt/src/curve25519.c | 6 +- wolfcrypt/src/ecc.c | 58 +++- wolfcrypt/src/ed25519.c | 42 ++- wolfcrypt/src/port/nxp/README_SE050.md | 29 ++ wolfcrypt/src/port/nxp/se050_port.c | 64 ++++ wolfcrypt/src/rsa.c | 23 +- wolfcrypt/test/test.c | 389 ++++++++++++++++++++++++- 8 files changed, 614 insertions(+), 25 deletions(-) diff --git a/.github/workflows/se050-sim.yml b/.github/workflows/se050-sim.yml index 7a5a7b27fb4..9799ddb3078 100644 --- a/.github/workflows/se050-sim.yml +++ b/.github/workflows/se050-sim.yml @@ -35,10 +35,22 @@ env: jobs: se050_sim: - name: wolfCrypt against SE050 simulator + name: wolfCrypt against SE050 simulator (${{ matrix.name }}) if: ${{ (github.repository_owner == 'wolfssl') && (github.event_name != 'pull_request' || github.event.pull_request.draft == false) }} runs-on: ubuntu-24.04 timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + # Default build: every keyed operation is offloaded to the SE050. + - name: default + extra_cflags: '' + # Per-key runtime HW/SW routing. The wolfCrypt test binary runs the + # ecc/ed25519/curve25519/rsa SE050_ONLY_KEY_ID coverage (software key + # vs SE050-resident key) added to wolfcrypt/test/test.c. + - name: only-key-id + extra_cflags: '-DWOLFSSL_SE050_ONLY_KEY_ID' steps: - name: Checkout wolfSSL (PR source) uses: actions/checkout@v5 @@ -75,9 +87,17 @@ jobs: file: simulators/SE050Sim/Dockerfile.wolfcrypt push: false load: true - tags: wolfssl-se050-sim:ci + tags: wolfssl-se050-sim:ci-${{ matrix.name }} + # WOLFSSL_EXTRA_CFLAGS is appended to the wolfSSL ./configure CFLAGS by + # the simulator's Dockerfile.wolfcrypt (ARG WOLFSSL_EXTRA_CFLAGS). When + # bumping SIMULATORS_REF, keep that ARG in place so the only-key-id + # matrix leg actually defines the macro. + build-args: | + WOLFSSL_EXTRA_CFLAGS=${{ matrix.extra_cflags }} + # Only the default leg refreshes the shared cache to avoid two matrix + # legs writing the same registry ref. cache-from: type=registry,ref=ghcr.io/wolfssl/wolfssl-sim-cache:se050 - cache-to: ${{ (github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && 'type=registry,ref=ghcr.io/wolfssl/wolfssl-sim-cache:se050,mode=max' || '' }} + cache-to: ${{ ((github.event_name == 'schedule' || github.event_name == 'workflow_dispatch') && matrix.name == 'default') && 'type=registry,ref=ghcr.io/wolfssl/wolfssl-sim-cache:se050,mode=max' || '' }} - name: Run wolfCrypt tests against simulator - run: docker run --rm wolfssl-se050-sim:ci + run: docker run --rm wolfssl-se050-sim:ci-${{ matrix.name }} diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index 12efe361f92..c53752d078c 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -585,7 +585,7 @@ int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key) #endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_X25519 && * WOLFSSL_ASYNC_CRYPT_SW */ -#ifdef WOLFSSL_SE050 +#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID) ret = se050_curve25519_create_key(key, keysize); #elif defined(WC_X25519_NONBLOCK) if (key->nb_ctx != NULL) { @@ -593,7 +593,9 @@ int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key) } else #endif -#if !defined(WOLFSSL_SE050) + /* Under WOLFSSL_SE050_ONLY_KEY_ID, generate a software key (keyIdSet == 0); + * its shared-secret computation routes through software (privSet == 1). */ +#if !defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID) { ret = wc_curve25519_make_priv(rng, keysize, key->k); if (ret == 0) { diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index ab8b42fb975..41d711303eb 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -286,7 +286,14 @@ ECC Curve Sizes: #undef HAVE_ECC_VERIFY_HELPER #define HAVE_ECC_VERIFY_HELPER #endif -#if defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) && defined(HAVE_ECC_VERIFY) +/* Compile in the software verify helper whenever SE050 hardware ECDSA verify is + * bypassed: + * - WOLFSSL_SE050_NO_ECDSA_VERIFY disables SE050 ECDSA verify outright. + * - WOLFSSL_SE050_ONLY_KEY_ID verifies software keys (keyIdSet == 0) in + * wolfCrypt; the SE050 is used at runtime only for keys resident in HW. */ +#if (defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) || \ + (defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID))) && \ + defined(HAVE_ECC_VERIFY) #define HAVE_ECC_VERIFY_HELPER #endif @@ -4716,6 +4723,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, word32* outlen) { int err = 0; + int privateKeyOk = 0; #if defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_ATECC508A) && \ !defined(WOLFSSL_ATECC608A) && !defined(WOLFSSL_MICROCHIP_TA100) @@ -4723,6 +4731,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, #endif (void)err; + (void)privateKeyOk; if (private_key == NULL || public_key == NULL || out == NULL || outlen == NULL) { @@ -4745,8 +4754,16 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, return NO_VALID_DEVID; #else /* !WOLF_CRYPTO_CB_ONLY_ECC */ /* type valid? */ - if (private_key->type != ECC_PRIVATEKEY && - private_key->type != ECC_PRIVATEKEY_ONLY) { + privateKeyOk = private_key->type == ECC_PRIVATEKEY || + private_key->type == ECC_PRIVATEKEY_ONLY; +#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) && \ + defined(WOLFSSL_SE050_ONLY_KEY_ID) + /* A SE050 key-id handle can represent a private key even though + * wc_ecc_use_key_id() only loads the public point into the ecc_key. */ + if (private_key->keyIdSet) + privateKeyOk = 1; +#endif + if (!privateKeyOk) { return ECC_BAD_ARG_E; } @@ -4789,6 +4806,15 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, err = silabs_ecc_shared_secret(private_key, public_key, out, outlen); #elif defined(WOLFSSL_KCAPI_ECC) err = KcapiEcc_SharedSecret(private_key, public_key, out, outlen); +#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) && \ + defined(WOLFSSL_SE050_ONLY_KEY_ID) + /* SE050-resident private key uses hardware ECDH; a software private key + * (keyIdSet == 0) uses the wolfCrypt software implementation. */ + if (private_key->keyIdSet) + err = se050_ecc_shared_secret(private_key, public_key, out, outlen); + else + err = wc_ecc_shared_secret_ex(private_key, &public_key->pubkey, out, + outlen); #elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) err = se050_ecc_shared_secret(private_key, public_key, out, outlen); #else @@ -5869,7 +5895,8 @@ static int _ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, else { err = NOT_COMPILED_IN; } -#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) +#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDHE) && \ + !defined(WOLFSSL_SE050_ONLY_KEY_ID) err = se050_ecc_create_key(key, key->dp->id, key->dp->size); key->type = ECC_PRIVATEKEY; #elif defined(WOLFSSL_CRYPTOCELL) @@ -6969,7 +6996,14 @@ int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, } /* hardware crypto */ -#if defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A) || \ +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) + /* Route by key location: SE050-resident keys sign in hardware, software + * keys (keyIdSet == 0) sign with the wolfCrypt software implementation. */ + if (key->keyIdSet) + err = wc_ecc_sign_hash_hw(in, inlen, r, s, out, outlen, rng, key); + else + err = wc_ecc_sign_hash_ex(in, inlen, rng, key, r, s); +#elif defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A) || \ defined(WOLFSSL_MICROCHIP_TA100) || \ defined(PLUTON_CRYPTO_ECC) || defined(WOLFSSL_CRYPTOCELL) || \ defined(WOLFSSL_SILABS_SE_ACCEL) || defined(WOLFSSL_KCAPI_ECC) || \ @@ -9461,8 +9495,11 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, #elif defined(WOLFSSL_XILINX_CRYPT_VERSAL) byte sigRS[ECC_MAX_CRYPTO_HW_SIZE * 2]; byte hashcopy[ECC_MAX_CRYPTO_HW_SIZE] = {0}; -#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) +#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) && \ + !defined(WOLFSSL_SE050_ONLY_KEY_ID) #else + /* Software verify helper (also used for SE050 software keys under + * WOLFSSL_SE050_ONLY_KEY_ID) needs the curve specs. */ int curveLoaded = 0; DECLARE_CURVE_SPECS(ECC_CURVE_FIELD_COUNT); #endif @@ -9497,6 +9534,15 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, return err; } +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \ + !defined(WOLFSSL_SE050_NO_ECDSA_VERIFY) + /* Key resident in the SE050: verify in hardware. Software keys fall through + * to the wolfCrypt verify helper below. */ + if (key->keyIdSet) { + return se050_ecc_verify_hash_ex(hash, hashlen, r, s, key, res); + } +#endif + keySz = (word32)key->dp->size; #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_ECC) && \ diff --git a/wolfcrypt/src/ed25519.c b/wolfcrypt/src/ed25519.c index 3cf8d807fec..3f148bd3d3d 100644 --- a/wolfcrypt/src/ed25519.c +++ b/wolfcrypt/src/ed25519.c @@ -429,7 +429,7 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out, const byte* context, byte contextLen) { int ret; -#ifdef WOLFSSL_SE050 +#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID) (void)context; (void)contextLen; (void)type; @@ -454,6 +454,20 @@ int wc_ed25519_sign_msg_ex(const byte* in, word32 inLen, byte* out, return BAD_FUNC_ARG; } +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) + /* Key resident in the SE050: sign in hardware. Software keys fall through + * to the wolfCrypt software implementation below. */ + if (key->keyIdSet) { + /* The SE050 performs only PureEdDSA; it cannot apply the Ed25519ctx or + * Ed25519ph variants, so reject them rather than silently signing with + * the wrong scheme. */ + if (type == Ed25519ctx || type == Ed25519ph || contextLen != 0) { + return BAD_FUNC_ARG; + } + return se050_ed25519_sign_msg(in, inLen, out, outLen, key); + } +#endif + if ((type == Ed25519ph) && (inLen != WC_SHA512_DIGEST_SIZE)) { @@ -696,7 +710,9 @@ int wc_ed25519ph_sign_msg(const byte* in, word32 inLen, byte* out, #endif /* HAVE_ED25519_SIGN */ #ifdef HAVE_ED25519_VERIFY -#ifndef WOLFSSL_SE050 +/* The software verify helpers are also needed under WOLFSSL_SE050_ONLY_KEY_ID + * so that software keys (keyIdSet == 0) can be verified in wolfCrypt. */ +#if !defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID) #ifdef WOLFSSL_CHECK_VER_FAULTS static const byte sha512_empty[] = { @@ -930,7 +946,8 @@ static int ed25519_verify_msg_final_with_sha(const byte* sig, word32 sigLen, } #endif /* WOLFSSL_SE050 */ -#if defined(WOLFSSL_ED25519_STREAMING_VERIFY) && !defined(WOLFSSL_SE050) +#if defined(WOLFSSL_ED25519_STREAMING_VERIFY) && \ + (!defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID)) int wc_ed25519_verify_msg_init(const byte* sig, word32 sigLen, ed25519_key* key, byte type, const byte* context, byte contextLen) { @@ -950,7 +967,8 @@ int wc_ed25519_verify_msg_final(const byte* sig, word32 sigLen, int* res, key, &key->sha); } -#endif /* WOLFSSL_ED25519_STREAMING_VERIFY && !WOLFSSL_SE050 */ +#endif /* WOLFSSL_ED25519_STREAMING_VERIFY && + * (!WOLFSSL_SE050 || WOLFSSL_SE050_ONLY_KEY_ID) */ /* sig is array of bytes containing the signature @@ -966,7 +984,7 @@ int wc_ed25519_verify_msg_ex(const byte* sig, word32 sigLen, const byte* msg, byte type, const byte* context, byte contextLen) { int ret; -#ifdef WOLFSSL_SE050 +#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID) (void)type; (void)context; (void)contextLen; @@ -979,6 +997,20 @@ int wc_ed25519_verify_msg_ex(const byte* sig, word32 sigLen, const byte* msg, WC_DECLARE_VAR(sha, wc_Sha512, 1, key ? key->heap : NULL); #endif +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) + /* Key resident in the SE050: verify in hardware. Software keys fall through + * to the wolfCrypt software implementation below. */ + if (key != NULL && key->keyIdSet) { + /* The SE050 performs only PureEdDSA; it cannot apply the Ed25519ctx or + * Ed25519ph variants, so reject them rather than silently verifying + * against the wrong scheme. */ + if (type == Ed25519ctx || type == Ed25519ph || contextLen != 0) { + return BAD_FUNC_ARG; + } + return se050_ed25519_verify_msg(sig, sigLen, msg, msgLen, key, res); + } +#endif + /* sanity check on arguments */ if (sig == NULL || msg == NULL || res == NULL || key == NULL || (context == NULL && contextLen != 0)) diff --git a/wolfcrypt/src/port/nxp/README_SE050.md b/wolfcrypt/src/port/nxp/README_SE050.md index ae10c916152..cc04349818f 100644 --- a/wolfcrypt/src/port/nxp/README_SE050.md +++ b/wolfcrypt/src/port/nxp/README_SE050.md @@ -265,6 +265,35 @@ offloaded to the SE050, but RSA PKCS#1 v1.5 verification (`wc_RsaSSL_Verify()`) uses wolfCrypt software (public-key exponentiation + unpad). RSA PSS verify and RSA key-exchange decrypt are unaffected. +**`WOLFSSL_SE050_ONLY_KEY_ID`** + +Requires `WOLFSSL_SE050`. By default every keyed operation is routed to the +SE050 at compile time. When this macro is defined, routing becomes a per-key +*runtime* decision based on `key->keyIdSet`: + +- A key resident in the SE050 (`keyIdSet == 1`, established via + `wc_ecc_use_key_id()`, `wc_se050_ecc_insert_private_key()`, `wc_RsaUseKeyId()`, + `wc_se050_rsa_insert_private_key()`, etc.) runs the operation on the SE050. +- A software key (`keyIdSet == 0`) runs the operation in wolfCrypt software. + +Because both paths must be available, the build compiles *both* the SE050 and +the wolfCrypt software implementations (larger code size). Key generation +(`wc_ecc_make_key()`, `wc_curve25519_make_key()`, `wc_MakeRsaKey()`; Ed25519 +key generation is already software-only) produces a *software* key +(`keyIdSet == 0`); it does not implicitly create a key inside the SE050. + +In-scope operations: ECC sign/verify/ECDH/keygen, Ed25519 sign/verify, +Curve25519 shared-secret/keygen, and RSA sign/verify/encrypt/decrypt/keygen. +RNG (TRNG) and hashing have no key and are unaffected. AES routing continues to +be governed by `WOLFSSL_SE050_CRYPT` and the AES `useSWCrypt` flag (the SE050 +AES path is opt-in and already chosen per-key at runtime). + +This macro composes with the `WOLFSSL_SE050_NO_*` macros above: if a `NO_*` +macro disables an operation, that operation always uses wolfCrypt software +regardless of `keyIdSet`. The SE050 port's "import a software key into the +SE050 on first use" behavior is disabled under this macro, so a software key is +never silently moved into hardware. + ## wolfSSL HostCrypto Support The NXP SE05x Plug & Trust Middleware by default can use either OpenSSL or diff --git a/wolfcrypt/src/port/nxp/se050_port.c b/wolfcrypt/src/port/nxp/se050_port.c index 0f5d8d57e5e..2ac56de558e 100644 --- a/wolfcrypt/src/port/nxp/se050_port.c +++ b/wolfcrypt/src/port/nxp/se050_port.c @@ -1231,6 +1231,14 @@ int se050_rsa_sign(const byte* in, word32 inLen, byte* out, return WC_HW_E; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + if (wolfSSL_CryptHwMutexLock() != 0) { return BAD_MUTEX_E; } @@ -1435,6 +1443,14 @@ int se050_rsa_verify(const byte* in, word32 inLen, byte* out, word32 outLen, return WC_HW_E; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + if (wolfSSL_CryptHwMutexLock() != 0) { return BAD_MUTEX_E; } @@ -1638,6 +1654,14 @@ int se050_rsa_public_encrypt(const byte* in, word32 inLen, byte* out, return WC_HW_E; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + if (wolfSSL_CryptHwMutexLock() != 0) { return BAD_MUTEX_E; } @@ -1806,6 +1830,14 @@ int se050_rsa_private_decrypt(const byte* in, word32 inLen, byte* out, return WC_HW_E; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + if (wolfSSL_CryptHwMutexLock() != 0) { return BAD_MUTEX_E; } @@ -2135,6 +2167,14 @@ int se050_ecc_sign_hash_ex(const byte* in, word32 inLen, MATH_INT_T* r, MATH_INT return BAD_FUNC_ARG; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + #ifndef WC_ALLOW_ECC_ZERO_HASH /* SE050 hardware does not reject all-zero digests; mirror the * software path's check so behavior is consistent. */ @@ -2316,6 +2356,14 @@ int se050_ecc_verify_hash_ex(const byte* hash, word32 hashLen, MATH_INT_T* r, return WC_HW_E; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + keySize = key->dp->size; ret = se050_map_curve(key->dp->id, keySize, &keySizeBits, &curveType); if (ret != 0) { @@ -2983,6 +3031,14 @@ int se050_ed25519_sign_msg(const byte* in, word32 inLen, byte* out, return WC_HW_E; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + if (wolfSSL_CryptHwMutexLock() != 0) { return BAD_MUTEX_E; } @@ -3087,6 +3143,14 @@ int se050_ed25519_verify_msg(const byte* signature, word32 signatureLen, return WC_HW_E; } +#ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Under ONLY_KEY_ID only SE050-resident keys reach this + * hardware path. Never auto-import a software key (keyIdSet == 0). */ + if (key->keyIdSet == 0) { + return NOT_COMPILED_IN; + } +#endif + if (wolfSSL_CryptHwMutexLock() != 0) { return BAD_MUTEX_E; } diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index cd66eab2efd..8a07cb3d5fa 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -3769,6 +3769,12 @@ static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out, return WC_HW_E; } #elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_RSA) + #ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Only offload to the SE050 when the key is resident in hardware; + * software keys (keyIdSet == 0) fall through to the software path. */ + if (key->keyIdSet) + #endif + { if (rsa_type == RSA_PUBLIC_ENCRYPT && pad_value == RSA_BLOCK_TYPE_2) { return se050_rsa_public_encrypt(in, inLen, out, outLen, key, rsa_type, pad_value, pad_type, hash, @@ -3785,6 +3791,7 @@ static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out, pad_value, pad_type, hash, mgf, label, labelSz, sz); } + } #endif /* RSA CRYPTO HW */ #if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_RSA_PAD) @@ -3949,6 +3956,12 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, * wc_RsaPSS_CheckPadding / wc_RsaPSS_VerifyCheck path which has the * digest available. */ #elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_RSA) + #ifdef WOLFSSL_SE050_ONLY_KEY_ID + /* Only offload to the SE050 when the key is resident in hardware; + * software keys (keyIdSet == 0) fall through to the software path. */ + if (key->keyIdSet) + #endif + { if (rsa_type == RSA_PRIVATE_DECRYPT && pad_value == RSA_BLOCK_TYPE_2) { ret = se050_rsa_private_decrypt(in, inLen, out, outLen, key, rsa_type, pad_value, pad_type, hash, @@ -3975,6 +3988,7 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out, return ret; } #endif /* !WOLFSSL_SE050_NO_RSA_VERIFY */ + } #endif /* RSA CRYPTO HW */ @@ -5375,7 +5389,8 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng) { #ifndef WC_NO_RNG #if !defined(WOLFSSL_CRYPTOCELL) && \ - (!defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_NO_RSA)) && \ + (!defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_NO_RSA) || \ + defined(WOLFSSL_SE050_ONLY_KEY_ID)) && \ !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \ !defined(WOLFSSL_MICROCHIP_TA100) #ifdef WOLFSSL_SMALL_STACK @@ -5423,7 +5438,8 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng) #elif defined(WOLFSSL_MICROCHIP_TA100) err = wc_Microchip_rsa_create_key(key, size, e); goto out; -#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_RSA) +#elif defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_RSA) && \ + !defined(WOLFSSL_SE050_ONLY_KEY_ID) err = se050_rsa_create_key(key, size, e); goto out; #else @@ -5777,7 +5793,8 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng) #endif /* WOLFSSL_CRYPTOCELL / SW only */ out: -#if !defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_SE050) +#if !defined(WOLFSSL_CRYPTOCELL) && \ + (!defined(WOLFSSL_SE050) || defined(WOLFSSL_SE050_ONLY_KEY_ID)) #ifdef WOLFSSL_SMALL_STACK if (key != NULL) { XFREE(p, key->heap, DYNAMIC_TYPE_RSA); diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 66bcfef3916..c859b104b92 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -29540,6 +29540,102 @@ static wc_test_ret_t rsa_certreq_test(RsaKey* key, RsaKey* keypub, #endif /* WOLFSSL_CERT_GEN && !NO_ASN_TIME && !WOLFSSL_NO_MALLOC && * WOLFSSL_CERT_REQ && !WOLFSSL_NO_MALLOC */ +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \ + !defined(WOLFSSL_SE050_NO_RSA) && !defined(WOLFSSL_SE050_NO_RSA_VERIFY) && \ + !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \ + !defined(WOLFSSL_RSA_VERIFY_ONLY) + +/* SE050 key ID for the ONLY_KEY_ID RSA test. Must be < SE050_KEYID_START. */ +#define SE050_ONLYKEYID_TEST_RSA_ID 51 + +/* Exercise both routing paths under WOLFSSL_SE050_ONLY_KEY_ID for RSA: a + * generated software key (keyIdSet == 0 -> wolfCrypt software) and the same key + * promoted into the SE050 (keyIdSet == 1 -> hardware). PKCS#1 v1.5 sign/verify + * are checked on each path and cross-checked for interoperability. */ +static wc_test_ret_t rsa_se050_onlykeyid_test(WC_RNG* rng) +{ + wc_test_ret_t ret; + RsaKey swKey, hwKey; + int swInit = 0, hwInit = 0; + byte* der = NULL; + int derSz; + byte in[32]; + byte sigSw[256]; + byte sigHw[256]; + byte plain[256]; + word32 inLen = (word32)sizeof(in); + int sigSwSz, sigHwSz, plainSz; + + XMEMSET(in, 7, sizeof(in)); + + ret = wc_InitRsaKey_ex(&swKey, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + swInit = 1; + + /* Key generation must produce a software key (keyIdSet == 0). */ + ret = wc_MakeRsaKey(&swKey, 2048, WC_RSA_EXPONENT, rng); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + if (swKey.keyIdSet != 0) { ret = WC_TEST_RET_ENC_NC; goto done; } + + /* Export and promote the same key material into the SE050. */ + der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (der == NULL) { ret = WC_TEST_RET_ENC_ERRNO; goto done; } + derSz = wc_RsaKeyToDer(&swKey, der, FOURK_BUF); + if (derSz < 0) { ret = WC_TEST_RET_ENC_EC(derSz); goto done; } + + ret = wc_se050_rsa_insert_private_key(SE050_ONLYKEYID_TEST_RSA_ID, der, + (word32)derSz); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + + ret = wc_InitRsaKey_ex(&hwKey, HEAP_HINT, devId); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + hwInit = 1; + ret = wc_RsaUseKeyId(&hwKey, SE050_ONLYKEYID_TEST_RSA_ID, 0); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + if (hwKey.keyIdSet != 1) { ret = WC_TEST_RET_ENC_NC; goto done; } + + /* Software path: sign + verify. */ + sigSwSz = wc_RsaSSL_Sign(in, inLen, sigSw, (word32)sizeof(sigSw), &swKey, + rng); + if (sigSwSz < 0) { ret = WC_TEST_RET_ENC_EC(sigSwSz); goto done; } + plainSz = wc_RsaSSL_Verify(sigSw, (word32)sigSwSz, plain, + (word32)sizeof(plain), &swKey); + if (plainSz < 0) { ret = WC_TEST_RET_ENC_EC(plainSz); goto done; } + if ((word32)plainSz != inLen || XMEMCMP(plain, in, inLen) != 0) { + ret = WC_TEST_RET_ENC_NC; goto done; + } + + /* Hardware path: sign + verify. */ + sigHwSz = wc_RsaSSL_Sign(in, inLen, sigHw, (word32)sizeof(sigHw), &hwKey, + rng); + if (sigHwSz < 0) { ret = WC_TEST_RET_ENC_EC(sigHwSz); goto done; } + plainSz = wc_RsaSSL_Verify(sigHw, (word32)sigHwSz, plain, + (word32)sizeof(plain), &hwKey); + if (plainSz < 0) { ret = WC_TEST_RET_ENC_EC(plainSz); goto done; } + if ((word32)plainSz != inLen || XMEMCMP(plain, in, inLen) != 0) { + ret = WC_TEST_RET_ENC_NC; goto done; + } + + /* Cross-verify: RSA PKCS#1 v1.5 is deterministic, so the software and + * hardware signatures over the same key and input must be identical. */ + if (sigSwSz != sigHwSz || XMEMCMP(sigSw, sigHw, (size_t)sigSwSz) != 0) { + ret = WC_TEST_RET_ENC_NC; goto done; + } + ret = 0; + +done: + if (der != NULL) + XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (hwInit) + wc_FreeRsaKey(&hwKey); + if (swInit) + wc_FreeRsaKey(&swKey); + (void)wc_se050_erase_object(SE050_ONLYKEYID_TEST_RSA_ID); + return ret; +} +#endif /* WOLFSSL_SE050 && WOLFSSL_SE050_ONLY_KEY_ID && !NO_MALLOC && ... */ + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_test(void) { wc_test_ret_t ret; @@ -29866,6 +29962,17 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t rsa_test(void) ret = rsa_even_mod_test(&rng, key); #endif +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \ + !defined(WOLFSSL_SE050_NO_RSA) && !defined(WOLFSSL_SE050_NO_RSA_VERIFY) && \ + !defined(WOLFSSL_NO_MALLOC) && !defined(WOLFSSL_RSA_PUBLIC_ONLY) && \ + !defined(WOLFSSL_RSA_VERIFY_ONLY) + ret = rsa_se050_onlykeyid_test(&rng); + if (ret != 0) { + printf("rsa_se050_onlykeyid_test failed!\n"); + goto exit_rsa; + } +#endif + exit_rsa: (void)bytes; @@ -42842,6 +42949,174 @@ static wc_test_ret_t ecc_test_all_deterministic_k(WC_RNG* rng) } #endif +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \ + defined(HAVE_ECC_SIGN) && defined(HAVE_ECC_VERIFY) && \ + defined(HAVE_ECC_KEY_EXPORT) + +/* SE050 key ID used by the ONLY_KEY_ID ECC test. Must be < SE050_KEYID_START so + * it does not collide with key IDs the SE050 port auto-allocates. */ +#define SE050_ONLYKEYID_TEST_ECC_ID 50 + +/* Promote a freshly generated software ECC key into the SE050 so that the + * returned hwKey has keyIdSet == 1 and routes its operations to hardware. The + * same private key material is used, so signatures interoperate between the + * software and hardware keys. */ +static wc_test_ret_t se050_onlykeyid_promote_ecc(ecc_key* swKey, ecc_key* hwKey, + word32 keyId) +{ + wc_test_ret_t ret; + byte der[256]; + word32 derSz; + + ret = wc_EccKeyToDer(swKey, der, (word32)sizeof(der)); + if (ret < 0) + return WC_TEST_RET_ENC_EC(ret); + derSz = (word32)ret; + + ret = wc_se050_ecc_insert_private_key(keyId, der, derSz); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_ecc_init_ex(hwKey, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + + ret = wc_ecc_use_key_id(hwKey, keyId, 0); + if (ret != 0) { + wc_ecc_free(hwKey); + return WC_TEST_RET_ENC_EC(ret); + } + if (hwKey->keyIdSet != 1) { + wc_ecc_free(hwKey); + return WC_TEST_RET_ENC_NC; + } + + return 0; +} + +/* Exercise both routing paths under WOLFSSL_SE050_ONLY_KEY_ID: a generated + * software key (keyIdSet == 0 -> wolfCrypt software) and the same key promoted + * into the SE050 (keyIdSet == 1 -> hardware). */ +static wc_test_ret_t ecc_se050_onlykeyid_test(WC_RNG* rng) +{ + wc_test_ret_t ret; + ecc_key swKey, hwKey; + int swInit = 0, hwInit = 0; + int verify; + byte hash[32]; + byte sigSw[ECC_MAX_SIG_SIZE]; + byte sigHw[ECC_MAX_SIG_SIZE]; + word32 sigSwSz = (word32)sizeof(sigSw); + word32 sigHwSz = (word32)sizeof(sigHw); + + XMEMSET(hash, 9, sizeof(hash)); + + ret = wc_ecc_init_ex(&swKey, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + swInit = 1; + + /* Key generation under WOLFSSL_SE050_ONLY_KEY_ID must produce a software + * key (keyIdSet == 0). */ + ret = wc_ecc_make_key_ex(rng, 32, &swKey, ECC_SECP256R1); + if (ret != 0) { + ret = WC_TEST_RET_ENC_EC(ret); + goto done; + } + if (swKey.keyIdSet != 0) { + ret = WC_TEST_RET_ENC_NC; + goto done; + } + + ret = se050_onlykeyid_promote_ecc(&swKey, &hwKey, + SE050_ONLYKEYID_TEST_ECC_ID); + if (ret != 0) + goto done; + hwInit = 1; + + /* Software path: sign + verify. */ + ret = wc_ecc_sign_hash(hash, (word32)sizeof(hash), sigSw, &sigSwSz, rng, + &swKey); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + verify = 0; + ret = wc_ecc_verify_hash(sigSw, sigSwSz, hash, (word32)sizeof(hash), + &verify, &swKey); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + if (verify != 1) { ret = WC_TEST_RET_ENC_NC; goto done; } + + /* Hardware path: sign + verify. */ + ret = wc_ecc_sign_hash(hash, (word32)sizeof(hash), sigHw, &sigHwSz, rng, + &hwKey); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + verify = 0; + ret = wc_ecc_verify_hash(sigHw, sigHwSz, hash, (word32)sizeof(hash), + &verify, &hwKey); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + if (verify != 1) { ret = WC_TEST_RET_ENC_NC; goto done; } + + /* Cross-verify: a software-key signature verifies under the hardware key + * and vice-versa (same key material, different routing). */ + verify = 0; + ret = wc_ecc_verify_hash(sigSw, sigSwSz, hash, (word32)sizeof(hash), + &verify, &hwKey); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + if (verify != 1) { ret = WC_TEST_RET_ENC_NC; goto done; } + verify = 0; + ret = wc_ecc_verify_hash(sigHw, sigHwSz, hash, (word32)sizeof(hash), + &verify, &swKey); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + if (verify != 1) { ret = WC_TEST_RET_ENC_NC; goto done; } + +#if defined(HAVE_ECC_DHE) && !defined(WOLFSSL_SE050_NO_ECDHE) + { + /* ECDH with the software key must match ECDH with the same key after it + * has been promoted into the SE050 (swKey and hwKey share material). + * Skipped under WOLFSSL_SE050_NO_ECDHE: with SE050 ECDH disabled the + * hardware key has no software private scalar to fall back on. */ + ecc_key peer; + int peerInit = 0; + byte secretSw[MAX_ECC_BYTES]; + byte secretHw[MAX_ECC_BYTES]; + word32 secretSwSz = (word32)sizeof(secretSw); + word32 secretHwSz = (word32)sizeof(secretHw); + + ret = wc_ecc_init_ex(&peer, HEAP_HINT, devId); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto done; } + peerInit = 1; + ret = wc_ecc_make_key_ex(rng, 32, &peer, ECC_SECP256R1); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto ecdh_done; } + + ret = wc_ecc_set_rng(&swKey, rng); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto ecdh_done; } + ret = wc_ecc_shared_secret(&swKey, &peer, secretSw, &secretSwSz); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto ecdh_done; } + + ret = wc_ecc_shared_secret(&hwKey, &peer, secretHw, &secretHwSz); + if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto ecdh_done; } + + if (secretSwSz != secretHwSz || + XMEMCMP(secretSw, secretHw, secretSwSz) != 0) { + ret = WC_TEST_RET_ENC_NC; + } + ecdh_done: + if (peerInit) + wc_ecc_free(&peer); + if (ret != 0) + goto done; + } +#endif /* HAVE_ECC_DHE && !WOLFSSL_SE050_NO_ECDHE */ + +done: + if (hwInit) + wc_ecc_free(&hwKey); + if (swInit) + wc_ecc_free(&swKey); + (void)wc_se050_erase_object(SE050_ONLYKEYID_TEST_ECC_ID); + return ret; +} +#endif /* WOLFSSL_SE050 && WOLFSSL_SE050_ONLY_KEY_ID && sign && verify && + * key export */ + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test(void) { wc_test_ret_t ret; @@ -42973,6 +43248,16 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test(void) } #endif +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \ + defined(HAVE_ECC_SIGN) && defined(HAVE_ECC_VERIFY) && \ + defined(HAVE_ECC_KEY_EXPORT) + ret = ecc_se050_onlykeyid_test(&rng); + if (ret != 0) { + printf("ecc_se050_onlykeyid_test failed!\n"); + goto done; + } +#endif + done: wc_FreeRng(&rng); @@ -44740,6 +45025,13 @@ static wc_test_ret_t curve25519_keyagree_test(WC_RNG* rng, if (ret != 0) return WC_TEST_RET_ENC_EC(ret); +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) + /* Under ONLY_KEY_ID, generated keys are software keys (keyIdSet == 0, + * privSet == 1); the shared-secret computation below runs in software. */ + if (userA->keyIdSet != 0 || userB->keyIdSet != 0) + return WC_TEST_RET_ENC_NC; +#endif + #ifdef HAVE_CURVE25519_SHARED_SECRET /* find shared secret key */ x = sizeof(sharedA); @@ -45961,12 +46253,13 @@ static wc_test_ret_t ed25519_kat_test(ed25519_key* key, ed25519_key* key2) sizeof(msg4) }; -#ifdef WOLFSSL_SE050 +#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID) /* Iter 5 uses RFC 8032 msg4 (~1023 bytes), which exceeds the NXP * Plug&Trust SDK's SE05X_TLV_BUF_SIZE_CMD = 900 byte APDU buffer: * EdDSASign fails with "Not enough buffer" before the command reaches * the secure element. Cap at 5 iterations until the SDK buffer is - * enlarged upstream. */ + * enlarged upstream. Under WOLFSSL_SE050_ONLY_KEY_ID these are software + * keys (keyIdSet == 0) with no APDU limit, so run all 6. */ for (i = 0; i < 5; i++) { #else for (i = 0; i < 6; i++) { @@ -46125,7 +46418,10 @@ static wc_test_ret_t ed25519_rare_sig_test(ed25519_key* key) if (ret != 0) return WC_TEST_RET_ENC_EC(ret); -#ifdef WOLFSSL_SE050 +/* Under WOLFSSL_SE050_ONLY_KEY_ID this software key (keyIdSet == 0) verifies + * through the wolfCrypt software path, which reports the software error codes; + * only the always-offload SE050 build returns WC_HW_E here. */ +#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID) #define RARE_ED_BAD_ENC_E WC_NO_ERR_TRACE(WC_HW_E) #define RARE_ED_BAD_SIG_E WC_NO_ERR_TRACE(WC_HW_E) #else @@ -46255,9 +46551,11 @@ static wc_test_ret_t ed25519_asn_test(ed25519_key* key3) /* Signing with a private-only key (no public loaded yet) is rejected on * the host with BAD_FUNC_ARG. The SE050 port instead fails inside * sss_se05x_key_store_set_ecc_keypair and returns WC_HW_E, so accept - * that alternate error code when built against an SE050. */ + * that alternate error code when built against an SE050. Under + * WOLFSSL_SE050_ONLY_KEY_ID this software key (keyIdSet == 0) takes the + * host path, so the host BAD_FUNC_ARG applies. */ ret = wc_ed25519_sign_msg(msg, 0, out, &outlen, key3); -#ifdef WOLFSSL_SE050 +#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_ONLY_KEY_ID) if (ret != WC_NO_ERR_TRACE(WC_HW_E)) #else if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) @@ -46312,6 +46610,74 @@ static wc_test_ret_t ed25519_asn_test(ed25519_key* key3) #endif /* NO_ASN */ #endif /* HAVE_ED25519_SIGN && HAVE_ED25519_KEY_EXPORT && HAVE_ED25519_KEY_IMPORT */ +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \ + defined(HAVE_ED25519_SIGN) && defined(HAVE_ED25519_VERIFY) + +/* Under WOLFSSL_SE050_ONLY_KEY_ID an Ed25519 key resident in the SE050 + * (keyIdSet == 1) routes its operations to hardware, which performs only + * PureEdDSA. Verify that the Ed25519ph / Ed25519ctx variants are rejected with + * BAD_FUNC_ARG rather than silently falling back to plain Ed25519. The routing + * guard rejects these variants before any hardware access, so a real resident + * object is not required: a software key with keyIdSet forced on exercises the + * exact branch added for the per-key routing. (There is no public API to load + * an SE050-resident Ed25519 key, and se050_ed25519_create_key is WOLFSSL_LOCAL, + * so the handle is simulated via the public keyIdSet field.) */ +static wc_test_ret_t ed25519_se050_onlykeyid_test(void) +{ + wc_test_ret_t ret; + ed25519_key key; + int keyInit = 0; + int verify = 0; + byte msg[32]; + byte ctx[4]; + byte sig[ED25519_SIG_SIZE]; + word32 sigSz = (word32)sizeof(sig); + + XMEMSET(msg, 5, sizeof(msg)); + XMEMSET(ctx, 1, sizeof(ctx)); + XMEMSET(sig, 0, sizeof(sig)); + + ret = wc_ed25519_init_ex(&key, HEAP_HINT, devId); + if (ret != 0) + return WC_TEST_RET_ENC_EC(ret); + keyInit = 1; + + /* Simulate an SE050-resident key (see note above). */ + key.keyId = 1; + key.keyIdSet = 1; + + /* Ed25519ph must be rejected for a resident key. */ + ret = wc_ed25519ph_sign_msg(msg, (word32)sizeof(msg), sig, &sigSz, &key, + NULL, 0); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + ret = WC_TEST_RET_ENC_NC; goto done; + } + + /* Ed25519ctx must be rejected for a resident key. */ + sigSz = (word32)sizeof(sig); + ret = wc_ed25519ctx_sign_msg(msg, (word32)sizeof(msg), sig, &sigSz, &key, + ctx, (byte)sizeof(ctx)); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + ret = WC_TEST_RET_ENC_NC; goto done; + } + + /* The ph/ctx rejection must also hold on the verify path. */ + ret = wc_ed25519ph_verify_msg(sig, (word32)sizeof(sig), msg, + (word32)sizeof(msg), &verify, &key, NULL, 0); + if (ret != WC_NO_ERR_TRACE(BAD_FUNC_ARG)) { + ret = WC_TEST_RET_ENC_NC; goto done; + } + + ret = 0; +done: + /* Clear the simulated handle so teardown stays on the software path. */ + key.keyIdSet = 0; + if (keyInit) + wc_ed25519_free(&key); + return ret; +} +#endif /* WOLFSSL_SE050 && WOLFSSL_SE050_ONLY_KEY_ID && sign && verify */ + WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed25519_test(void) { wc_test_ret_t ret; @@ -46377,6 +46743,12 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed25519_test(void) ret = wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, key2); if (ret != 0) ERROR_OUT(WC_TEST_RET_ENC_EC(ret), cleanup); +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) + /* Under ONLY_KEY_ID, generated keys are software keys (keyIdSet == 0); the + * sign/verify below therefore exercises the wolfCrypt software path. */ + if (key->keyIdSet != 0 || key2->keyIdSet != 0) + ERROR_OUT(WC_TEST_RET_ENC_NC, cleanup); +#endif #endif /* helper functions for signature and key size */ @@ -46438,6 +46810,13 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ed25519_test(void) #endif /* WOLFSSL_CERT_GEN */ #endif /* WOLFSSL_TEST_CERT */ +#if defined(WOLFSSL_SE050) && defined(WOLFSSL_SE050_ONLY_KEY_ID) && \ + defined(HAVE_ED25519_SIGN) && defined(HAVE_ED25519_VERIFY) + ret = ed25519_se050_onlykeyid_test(); + if (ret != 0) + goto cleanup; +#endif + cleanup: /* clean up keys when done */