Fenrir fixes 2026 09 23 - #31
Open
danielinux wants to merge 31 commits into
Open
danielinux wants to merge 31 commits into
danielinux wants to merge 31 commits into
Conversation
psa_copy_key left a caller-supplied nonzero target identifier untouched when validation or storage init failed before the import; the API guarantees PSA_KEY_ID_NULL on failure. Starts the zero-capacity buffer regression test (copy_key lane) and registers it in the build.
A (NULL, 0) request is a valid buffer representation; skip the RNG backend, which rejects the NULL pointer, when output_size is zero.
psa_export_key/psa_export_public_key and the raw ECC export helper rejected data == NULL before the size check; (NULL, 0) must reach the BUFFER_TOO_SMALL path. Map the ECC LENGTH_ONLY_E probe to BUFFER_E.
psa_hash_finish rejected hash == NULL before the digest size check; a (NULL, 0) finish must yield BUFFER_TOO_SMALL.
psa_hash_compare rejected a NULL reference before the length check; a zero-length reference cannot match a fixed-size digest and is a verification mismatch.
wolfpsa_mac_final rejected mac == NULL before the length check; a (NULL, 0) finish must yield BUFFER_TOO_SMALL.
psa_encapsulate rejected ciphertext == NULL before clearing the outputs and checking the required size; a valid (NULL, 0) request must yield BUFFER_TOO_SMALL with the outputs cleared.
A malformed PKCS#1 v1.5 signature surfaced as GENERIC_ERROR because wc_error_to_psa_status had no RSA_PAD_E case.
WOLFPSA_HASH_MAX_SIZE covers the largest digest the engine accepts: a SHAKE-only build exposes 64-byte output while PSA_HASH_MAX_SIZE stays 32. Use it for the stack digests in hash verify/compare and the sign/verify message workers.
The encrypt/decrypt dispatch, the sign workers and raw key agreement required the output pointer unconditionally; a (NULL, 0) request must reach the required-size check and yield BUFFER_TOO_SMALL. The RSA workers check capacity before the backend call, which writes to the output buffer before it detects a short buffer. Grow the OAEP test buffer to the contract maximum.
The verify workers rejected signature == NULL before the length check; a zero-length signature cannot verify and is a mismatch.
psa_aead_generate_nonce and wolfpsa_aead_encrypt_final rejected the pointer before the size check; (NULL, 0) must yield BUFFER_TOO_SMALL.
wolfpsa_aead_decrypt_final rejected tag == NULL before the length check; (NULL, 0) is a tag-length mismatch. Check the tag before the plaintext capacity, matching the reference implementation's ordering.
psa_cipher_generate_iv rejected iv == NULL before the size check; (NULL, 0) must yield BUFFER_TOO_SMALL.
The X25519 export derived the public key with the keyless wc_curve25519_make_pub, which routes to whichever device happens to be registered and defeats a configured devId; derive through a key object bound to the default devId (with the blinding RNG the keyless path set up for itself). The agreement paths accept a (NULL, 0) output buffer.
The worker accepts SIGN_HASH algorithms (ECDSA, RSA, ML-DSA); HMAC is not among them.
The comment claimed the sizing was for psa_hash_suspend(); this build returns NOT_SUPPORTED for that API, so state the PSA formula.
wolfpsa_aead_ccm_ctr_inc dropped the carry-in history: a zero counter byte with no incoming carry re-armed the carry, corrupting every increment with lenSz >= 3 (CCM nonces shorter than 13 bytes) past the first block; tags still matched, so the divergence was silent. Add a 12-byte nonce multipart lane that fails on the buggy code.
Import one-sided usage keys and assert the opposite one-shot path returns NOT_PERMITTED before any crypto runs; the sub-cases now assert the import instead of skipping silently.
psa_cipher_encrypt/decrypt did pointer arithmetic on the output before the size check; a (NULL, 0) buffer is legal and must pass through as NULL.
psa_cipher_finish accepted a NULL output with nonzero size; reject it as INVALID_ARGUMENT before the backend call.
The setter may run on a control thread while the getter is called from crypto threads; the non-atomic access is a data race. Relaxed ordering is enough - a stale value only delays enforcement.
The XChaCha20-Poly1305 multipart finalization left the computed tag on the stack; zeroize it on every exit.
ccm_init left B0, the A chaining value and AAD blocks in the stack block buffer; route every exit through a single zeroize.
ccm_update left CBC-MAC output blocks in the tmp buffer; zeroize on every exit, including the AAD branch.
ccm_finish left the final MAC block and the S0 keystream block in the tmp buffer; zeroize on every exit.
danielinux
force-pushed
the
fenrir-fixes-2026-09-23
branch
from
September 23, 2026 14:59
09c5ec8 to
fa1aed4
Compare
The CTF suite (test_c041 psa_sign_hash, test_c052 psa_sign_message) passes a NULL hash/input pointer with zero length in its invalid-key-type checks and expects PSA_ERROR_INVALID_ARGUMENT. The zero-capacity pointer relaxation let those calls fall through to the key-type dispatch, returning NOT_SUPPORTED/NOT_PERMITTED instead.
danielinux
force-pushed
the
fenrir-fixes-2026-09-23
branch
from
September 23, 2026 15:52
ebd6b75 to
6e5ecde
Compare
wolfSSL-Fenrir-bot
previously requested changes
Sep 23, 2026
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #31
Scan targets checked: wolfpsa-src, wolfpsa-bugs
Findings: 4
4 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Reported findings require changes before merge.
- PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE bounds the plaintext, it is not its length, so requiring it rejected buffers that were big enough - decrypt into a modulus-sized scratch buffer and report BUFFER_TOO_SMALL from the unpadded length; drops the unsigned underflow when the padding exceeds the modulus - test: restore the 13-byte buffer the precondition had forced to 62, and cover the short-buffer case
- wc_RsaPrivateDecrypt reports a failed unpad as RSA_PAD_E, which the shared mapper turned into INVALID_SIGNATURE - map it to INVALID_PADDING, and override it locally in the verify path where a failed unpad is a signature mismatch
- the X25519/X448 export helpers rejected output == NULL before the size check, returning INVALID_ARGUMENT where RSA and the other ECC families return BUFFER_TOO_SMALL
- the encrypt-only imports treat NOT_SUPPORTED as a skip; the decrypt-only ones asserted SUCCESS and failed the whole suite on a build without XChaCha20-Poly1305 or Ascon-AEAD128
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #31
Scan targets checked: wolfpsa-src, wolfpsa-bugs
Fenrir result: Approved ✅
No new issues found in the changed files.
Advisory only — this automated result does not count as a GitHub approval.
wolfSSL-Fenrir-bot
dismissed
their stale review
September 23, 2026 18:49
Fenrir's latest completed scan found no issues; clearing the prior automated change request.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fa1aed4 F-13922: zeroize the CCM finish stack state
c39be3d F-13921: zeroize the CCM update stack state
d13e2cf F-13920: zeroize the CCM init stack state
2437e05 F-13914: zeroize the computed tag in multipart verify
8e35163 F-13913: make the interruptible max-ops counter atomic
21020d6 F-13912: validate the finish output pointer
b655273 F-13911: accept NULL zero-length one-shot buffers
185cf5e F-13890: negative usage-policy coverage for XChaCha20 and Ascon
07d3e95 F-13880: fix the CCM counter carry re-arm
14c6fc0 F-13874: correct the suspend buffer size comment
33824fb F-13873: drop HMAC from the sign_hash worker comment
286bf05 F-13857: honor the devId in X25519/X448 export
e1f4a64 F-13872: accept a zero-capacity generate_iv buffer
289b4fa F-13871: report INVALID_SIGNATURE for an empty tag
6066f58 F-13870: accept NULL zero-capacity nonce and tag buffers
d2da172 F-13869: report INVALID_SIGNATURE for an empty signature
fe23dd1 F-13868: accept NULL zero-capacity output buffers
7ea9366 F-13858: size the digest buffers for SHAKE output
cfa0aea F-13867: map RSA_PAD_E to INVALID_SIGNATURE
3938516 F-13866: accept a zero-capacity ciphertext in encapsulate
9032c9e F-13865: report BUFFER_TOO_SMALL for a zero-capacity finish
f35028b F-13864: report INVALID_SIGNATURE for an empty reference digest
ecd9744 F-13863: report BUFFER_TOO_SMALL for a zero-capacity finish
c18851e F-13862: accept NULL zero-capacity export buffers
be2612c F-13861: accept a zero-byte generation request
0318faf F-13860: clear the copy_key target id on failure