Skip to content

Fenrir fixes 2026 09 23 - #31

Open
danielinux wants to merge 31 commits into
wolfSSL:masterfrom
danielinux:fenrir-fixes-2026-09-23
Open

danielinux wants to merge 31 commits into
wolfSSL:masterfrom
danielinux:fenrir-fixes-2026-09-23

Conversation

@danielinux

@danielinux danielinux commented Sep 23, 2026

Copy link
Copy Markdown
Member

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

Copilot AI lite review requested due to automatic review settings September 23, 2026 14:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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
danielinux force-pushed the fenrir-fixes-2026-09-23 branch from 09c5ec8 to fa1aed4 Compare September 23, 2026 14:59
@danielinux danielinux self-assigned this Sep 23, 2026
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.

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/psa_rsa.c Outdated
Comment thread src/psa_engine.c Outdated
Comment thread test/psa_server/psa_ascon_xchacha_test.c Outdated
Comment thread src/psa_montgomery.c
- 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 wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants