Skip to content

Validate key and ciphertext lengths before passing them to liboqs - #161

Merged
dstebila merged 1 commit into
mainfrom
fix-ghsa-w696-length-checks
Oct 28, 2026
Merged

dstebila merged 1 commit into
mainfrom
fix-ghsa-w696-length-checks

Conversation

@dstebila

Copy link
Copy Markdown
Member

ctypes.create_string_buffer(value, length) silently zero-pads a value shorter than length. As a result, these APIs accepted short inputs and passed a different, zero-padded value to liboqs:

  • Signature.verify and Signature.verify_with_ctx_str (public key)
  • KeyEncapsulation.encap_secret (public key)
  • KeyEncapsulation.decap_secret (ciphertext)
  • the secret_key argument of the Signature and KeyEncapsulation constructors

StatefulSignature.verify sized its public key buffer to the input instead, so liboqs read past the end of a short key.

This PR raises ValueError unless each public key, ciphertext and secret key is exactly the length the algorithm requires. The constructors now also reject an empty secret_key instead of ignoring it.

Behaviour change: callers that passed wrong-length inputs and relied on them being padded will now get a ValueError.

Tests: new tests check that 0-byte, 32-byte, one-byte-short and one-byte-long inputs are rejected for every enabled KEM, signature and stateful signature algorithm. The two test_free_twice tests now pass a full-length secret key. Locally, the full suite passes (1908 tests) against liboqs 0.16.0 built with LMS and XMSS enabled.

🤖 Generated with Claude Code

ctypes.create_string_buffer(value, length) silently zero-pads a value
shorter than length, so Signature.verify, verify_with_ctx_str,
KeyEncapsulation.encap_secret and decap_secret, and the secret_key
argument of both constructors accepted short inputs and passed a
different, zero-padded value to liboqs. StatefulSignature.verify sized
its public key buffer to the input instead, so liboqs read past the end
of a short key.

Raise ValueError unless each public key, ciphertext and secret key is
exactly the length the algorithm requires, and reject an empty
secret_key instead of ignoring it. Add tests that 0-byte, 32-byte, one
byte short and one byte long inputs are rejected for every enabled
algorithm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Douglas Stebila <dstebila@uwaterloo.ca>
@dstebila dstebila self-assigned this Oct 28, 2026
@dstebila
dstebila merged commit 4c3b30a into main Oct 28, 2026
10 checks passed
@dstebila
dstebila deleted the fix-ghsa-w696-length-checks branch October 28, 2026 15:25
dstebila added a commit that referenced this pull request Oct 28, 2026
Maintenance release of liboqs-python 0.16.0 carrying the fix for
GHSA-w696-4vrr-x6x3 (ML-DSA signature forgery and ML-KEM shared-secret
recovery when an application passes an empty or very short public key).
It still pairs with liboqs 0.16.0.

- Bump version 0.16.1-dev -> 0.16.0.2 (pyproject.toml); the runtime
  auto-installer maps this to the liboqs 0.16.0 tag.
- CHANGES.md: add the 0.16.0.2 section.
- RELEASE.md: rewrite for 0.16.0.2, leading with the security fix and
  listing the behavior changes from #160 and #161.

Signed-off-by: Douglas Stebila <dstebila@uwaterloo.ca>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant