* Add wc_ecc_key_new_ex
Rust wrapper: use wc_ecc_key_new_ex for ECC when available.
Fixes F-8300.
* Check devId after wc_ecc_key_new_ex() call in unit test
WOLFSSL_SE050 enables WOLFSSL_KEY_TO_DER, but the original ASN implementation only compiled SetASNIntMP and SetBitString when unrelated features such as ECC or key generation were enabled. An ECC-free SE050 build therefore compiled the RSA DER callers without these helpers and failed at link time.
Include WOLFSSL_KEY_TO_DER in both helper guards, while retaining the NO_CERTS constraint for the public-key BIT STRING encoder. This allows SE050 RSA builds to disable HAVE_ECC without unresolved ASN symbols.
AF_ALG's decrypt entry points return KEYUSAGE_E from their aes->dir check,
and wc_AesGcmEncrypt returns BAD_FUNC_ARG on the unset socket, both before
wc_AesSetup's key check. aes_no_key_set_test expects MISSING_KEY and failed
on --enable-afalg. Guard each mode entry point ahead of those checks.
AF_ALG also set keyInstalled before copying the key, so a key setup that
failed on the socket left a keyless context marked as keyed. Move both
assignments after the copy.
aes.c undefines MAX3266X_AES for MAX3266X_CB builds, after aes.h has been
processed, so those builds took the software and callback paths with the
check compiled out. Keep the check enabled for them.
wc_AesSetKeyLocal set keyInstalled before the key schedule was built, so the
failure returns after that point (AES-NI SAVE_VECTOR_REGISTERS2/BAD_ALIGN_E,
the hardware key installs) left a context that passed WC_AES_KEY_IS_SET with
an all-zero schedule. Split the body out and derive keyInstalled from its
return value, so only a completed setup marks the context keyed.
The WOLF_CRYPTO_CB_SETKEY path sets keylen for a device-held key but has no
software schedule, which took AES-XTS past its keylen == 0 guard and into an
encrypt with rounds == 0. Reject a zero rounds in the XTS entry points too;
XTS has no crypto callback dispatch, so a device-held key is unusable there.
AES-KW/KWP guarded ahead of its per-block loop, but with HAVE_AES_ECB that
loop calls wc_AesEcbEncrypt, whose own guard sits after the crypto callback
dispatch. Device-held keys were rejected where they previously ran on the
device; keep the guard only for the direct-block path.
The CFB/CFB1/CFB8/OFB helpers and the PIC32MZ CBC entry points returned 0 for
a zero-length call on an unkeyed context while any other length returned
MISSING_KEY. Check the key first. AES-CBC keeps its zero-length return above
the offload dispatches, which must not see sz == 0.
The PSoC6 wc_AesSetKey tested aes != NULL after already passing it to
wc_Psoc6_Aes_SetKey; validate it up front instead.
wc_CryptoCb_SetKey() success returned straight out of wc_AesSetKey without
recording keylen or keyInstalled, unlike the WOLF_CRYPTO_CB_AES_SETKEY path
just above it, so a device-managed key set that way was then rejected by
the new guards.
Also document why wc_AesInit_Id()/wc_AesInit_Label() deliberately leave
keyInstalled clear: those contexts name a device-held key and have no
software schedule, so falling through to a software path is exactly the
case the guard exists to catch.
wc_Aes{En,De}cryptDirect ran the software schedule with no key check.
wc_AesKeyWrap_ex/UnWrap_ex validate only pointers and sizes before
looping on the wc_AesEncryptDirect macro, which expands to wc_AesEncrypt
and so bypasses a guard on the public function; they need their own.
Without a key wc_AesEncrypt returned KEYUSAGE_E from its rounds check,
so these now report MISSING_KEY like the mode APIs instead.
Add WOLFSSL_AES_DIRECT and HAVE_AES_KEYWRAP to aes_no_key_set_test's
outer condition, which also makes the test compile on DIRECT-only or
keywrap-only builds, and cover the four APIs there.
The keyInstalled guard is only reachable on the software mode paths.
Backends that replace an entry point with a hardware arm in aes.c or a
port file never reach it, so wolfcrypt_test's aes_no_key_set_test fails
there (reported on STM32). Gate the guard and the test on
WOLFSSL_AES_REQUIRE_KEY_SET, on by default and off automatically for
those backends. WOLFSSL_NO_AES_KEY_SET_CHECK forces it off; defining
WOLFSSL_AES_REQUIRE_KEY_SET forces it on. The struct member is always
maintained so the layout does not depend on the option.
Also fix three cases where the flag itself was wrong:
- Renesas FSPSM CRYPTONLY wc_AesSetKey never set it, so wc_AesCfb1/8,
which have no crypto-cb dispatch, rejected a correctly keyed context.
- TI wc_AesInit did not zero the struct, leaving the flag indeterminate.
- wc_AesFree returned early on the crypto-cb path without reaching the
ForceZero, leaving the flag set on a freed context.
The swdev harness (--enable-swdev) defines WOLF_CRYPTO_CB_FIND, which
compiles out the 'devId != INVALID_DEVID' guard in the AES mode entry
points. Every AES call is then dispatched to the crypto callback
regardless of devId, so the software keyInstalled guard is unreachable
and the callback rejects a missing key with its own error rather than
MISSING_KEY. aes_no_key_set_test asserts MISSING_KEY exactly, so it
aborted every swdev/cryptocb-only config. Skip the test when
WOLF_CRYPTO_CB_FIND is defined.
- Move Aes.keyInstalled to the end of struct Aes so existing member
offsets are unchanged (avoids an ABI break) and it is available in all
configs that set it.
- Report a missing key with MISSING_KEY instead of BAD_FUNC_ARG in the AES
mode guards (aes.c and the AF_ALG backend), splitting the combined
NULL/no-key checks so a NULL argument still returns BAD_FUNC_ARG. Update
the no-key self test accordingly.
- Make sz==0 handling consistent: return 0 before the no-key guard in the
CFB/OFB/CFB1/CFB8 and PIC32MZ CBC paths, and add an sz==0 early return to
wc_AesCtrEncrypt.
- Place the RISC-V AES-CBC path after the DCP and crypto callback
dispatches so a single key guard sits after all offload dispatches.
The AF_ALG AES mode overrides route through wc_AesSetup, which called
setsockopt(ALG_SET_KEY, key, 0) with keylen 0 and returned WC_AFALG_SOCK_E
instead of BAD_FUNC_ARG when no key was installed, so aes_no_key_set_test
failed on WOLFSSL_AFALG. Reject setup when keyInstalled is 0, matching the
software backend's no-key guard. Covers CBC, CTR, ECB and GCM.
The keyInstalled guard added to the shared aes.c mode functions is set by
every in-aes.c key-schedule branch except FREESCALE_LTC and FREESCALE_MMCAU.
Their wc_AesSetKeyLocal installs the key but left keyInstalled at 0, so any
guarded AES mode that falls through to a shared aes.c path returned an error
after a valid key setup on those ports.
Set keyInstalled at the key-install point in both branches, matching the
other ports fixed earlier in this PR.
The RISC-V assembly CBC encrypt/decrypt paths return before the generic
keyInstalled guard, so wc_AesCbcEncrypt/Decrypt accepted a call with no
key set. aes_no_key_set_test caught this on the riscv64-o0 config. Add
the guard to the RISC-V dispatch, matching the other backends.
The keyInstalled guard added to the shared aes.c mode functions is only
set by aes.c's own key schedule and the RISC-V port. Ports that ship
their own compile-time wc_AesSetKey/wc_AesGcmSetKey left keyInstalled at
0, so any AES mode that falls through to a guarded aes.c path returned
BAD_FUNC_ARG after a correct key setup.
Set keyInstalled at the key-install point of the affected ports so the
shared mode guards accept a validly-keyed context:
- silabs, af_alg, devcrypto, ti, caam: wc_AesSetKey
- af_alg, kcapi: wc_AesGcmSetKey
In the software CFB/CFB1/CFB8/OFB helpers the sz == 0 early return came
before the keyInstalled check, so a no-key call succeeded with sz == 0
but failed with sz > 0. Check the key first; crypto callbacks already
ran in the callers. CBC keeps its sz == 0 return first because the DCP
dispatch below it cannot handle sz == 0 (reads out + sz - 16); comment
the ordering there.
CCM has the same zero-key exposure as GCM: CBC-MAC and CTR run against
the all-zero key schedule left by wc_AesInit. Add the keyInstalled guard
to the software CCM encrypt/decrypt paths, mirroring GCM, and to the
RISC-V port so it returns BAD_FUNC_ARG instead of KEYUSAGE_E. Extend
aes_no_key_set_test with CCM cases.
Address review feedback on the negative tampered-digest assertion, which
encoded ret via WC_TEST_RET_ENC_EC(ret). That is in fact non-zero even
for ret == 0, but switch to WC_TEST_RET_ENC_NC so the failure code is
unambiguously non-zero and independent of ret. Verified by mutation:
deleting the signature-to-message hash compare still fails the test.
Under FIPS/selftest the AES functions come from the validated module,
which does not reject use before a key is installed, so
aes_no_key_set_test failed on the CAVP selftest and FIPS customer-config
CI jobs. The keyInstalled guard is a non-FIPS hardening, so gate the test
on !HAVE_FIPS && !HAVE_SELFTEST. The FIPS CASTs (wc_RunAllCast_fips) pass,
confirming the change does not affect validated AES.
aes_no_key_set_test runs on every CI backend and exposed two ports whose
own mode functions ran with an unset key. Other hardware backends (STM32,
the secure-element sims) already reject this via wc_AesGetKeySize.
- PIC32MZ: guard wc_AesCbcEncrypt/Decrypt. keyInstalled is already set
through wc_AesSetKeyLocal, the generic SetKey funnel these use.
- RISC-V assembly: set keyInstalled in all three wc_AesSetKey variants
and guard CBC/ECB/GCM encrypt and decrypt. CTR already rejects via its
rounds switch.
Address review of the keySet bitfield:
- Rename keySet to keyInstalled. struct Aes already has a Cavium-only
keySet member (HAVE_CAVIUM_OCTEON_SYNC), so an unconditional keySet
bitfield was a duplicate that would not compile on that build.
- Set keyInstalled on every key install, not just the software funnel.
The ARM, PPC64 and other hardware wc_AesSetKey/SetKeyDirect variants
populate keylen/rounds directly; without also setting the flag they
would have made the shared mode APIs reject a validly-keyed context.
The flag is now set at every keylen-assignment point in aes.c and in
the PSOC6 SetKey wrapper.
Replace the keylen == 0 guards with a new Aes.keySet bitfield, set by the
key-installation paths and checked in the mode APIs. keylen alone is not
a reliable "key installed" signal across backends: some ports map a zero
key length to a default (e.g. PSOC6 maps keylen 0 to AES-128), so a
keylen-based check placed only in the software paths left those builds
running with the all-zero key schedule and would fail aes_no_key_set_test.
keySet is set in wc_AesSetKeyLocal (the funnel for the software
SetKey/SetKeyDirect/GcmSetKey paths) and in the PSOC6 wc_AesSetKey
wrapper, and checked in the public CBC/CTR/GCM/ECB/CFB/OFB entry points,
including the PSOC6 port variants.
wc_RsaPSS_CheckPadding_ex2 binds a PSS signature to the message with a
single comparison of the recomputed hash against the encoded hash H.
Every positive PSS test passes the correct digest and the negative tests
use a wrong salt length that fails before that comparison is reached, so
deleting the comparison left all default tests passing even though any
well-formed PSS structure would then verify against any message.
After each successful sign/verify round-trip in rsa_pss_test, flip one
bit of the message digest, keep the correct salt length, and require
BAD_PADDING_E. This makes the hash comparison the deciding check and
catches its removal.
wc_AesInit zeroes the Aes struct, leaving keylen and rounds at 0. The
CTR/CBC/GCM/ECB/CFB/OFB entry points never verified that a key had been
installed with wc_AesSetKey, so calling them right after wc_AesInit ran
the software cipher against an all-zero key schedule and returned
success instead of an error. For CTR this exposes a reconstructable
keystream; for GCM the hash subkey H is also zero, making the tag
forgeable.
Add the keylen == 0 guard already used by wc_AesXtsEncrypt to the
software mode paths. The check is placed after the crypto callback
fall-through so device-managed keys are unaffected. Hardware paths that
call wc_AesGetKeySize already reject this case via rounds == 0.
Add aes_no_key_set_test(), run from aes_test(), which inits an Aes
context and confirms every mode rejects use before a key is set.