Commit Graph

385 Commits (afcebbf946e0e5865e18df3682e8af18dcc0f572)

Author SHA1 Message Date
Martijn de Milliano afcebbf946 Rename flag to ML_DSA_NO_CTX_ENABLED 2026-06-29 18:41:17 +02:00
Martijn de Milliano 408ac74e9a Move MIN_AUTH_TAG_SZ next to AES-GCM-stream
This place is more logical
2026-06-29 18:41:01 +02:00
Martijn de Milliano f8e56cd063 ML-DSA: fix ML_DSA_NO_CTX detection and add to default features
Also detect WOLFSSL_DILITHIUM_FIPS204_DRAFT as implying no-ctx support,
mirroring the logic in dilithium.h. Add ML_DSA_NO_CTX to the default
features dict for consistency with peer flags.
2026-06-26 00:35:32 +02:00
Martijn de Milliano fc5ea53605 Update AESGCM test
Read minimum supported tag size from settings and make the
test less ambiguous.
2026-06-26 00:31:05 +02:00
Martijn de Milliano aec3f2d553 Add tests for no-context signing 2026-06-26 00:10:34 +02:00
Martijn de Milliano 8d87cb4d13 ML-DSA: fix wording of message and docstrings 2026-06-26 00:05:15 +02:00
Martijn de Milliano eb93f657bf Test AESGCM stream: ignore failures for small auth tags
Smaller authentication tags may not be supported by the library.
This fix makes the test work for the default case that tags
should be minimum 12 bytes in size.
2026-06-04 18:05:58 +02:00
Martijn de Milliano 52886c4034 ML-DSA: Deal with signing without context not always supported
In the newer wolfSSL signing and verifying without context is
not available unless it is explicitly enabled.

This change modifies the Python binding and test suite to
accommodate this.
2026-06-04 18:03:35 +02:00
Martijn de Milliano 1e20bc9b80 Prepare for v5.9.1 release 2026-06-04 16:59:24 +02:00
David Garske aa34a9c67d
Merge pull request #112 from roberthdevries/remove-unicode-prefix
Remove unicode prefix.
2026-05-17 22:32:20 -07:00
David Garske f0c187a7ad
Merge pull request #120 from roberthdevries/use-f-string-instead-of-percent-formatting
Use f string instead of percent formatting
2026-05-17 22:03:16 -07:00
Robert de Vries 18701e3b62 Use format specifiers instead of percent format.
printf-style string formatting has a number of quirks, and leads to less
readable code than using str.format calls or f-strings.
In general, prefer the newer str.format and f-strings constructs over
printf-style string formatting.
2026-05-17 16:14:52 +02:00
Robert de Vries 31475dddac Remove unicode prefix.
In Python 3, all strings are Unicode by default. The Unicode kind prefix is
unnecessary and should be removed to avoid confusion.
2026-05-17 15:00:03 +02:00
David Garske 8b3acfc12a
Merge pull request #119 from LinuxJedi/f-fixes2
Address Fenrir findings
2026-05-12 09:29:01 -07:00
Andrew Hutchings ef4195f99a Address Fenrir findings
F-3340: AesGcmStream.final decrypt path passed len(authTag) straight to
wc_AesGcmDecryptFinal, letting a caller truncate the verification window
(forgery probability ~2^-32 instead of 2^-128 for a 4-byte tag against a
16-byte configuration). Reject len(authTag) != self._tag_bytes and pass
self._tag_bytes to wolfSSL, mirroring ChaCha20Poly1305.decrypt. Added
test_decrypt_rejects_wrong_tag_length. Also fixed test_encrypt_short_tag
which was relying on the bug (decrypt side defaulted to tag_bytes=16
against a 12-byte tag).

F-3089: Declare label as const byte* in the wc_RsaPublicEncrypt_ex and
wc_RsaPrivateDecrypt_ex cdefs so CFFI can accept Python bytes without
exposing a writable pointer into immutable memory. wolfSSL does not
modify label.

F-3090: Declare nonce as const byte* in the wc_InitRngNonce and
wc_InitRngNonce_ex cdefs for the same reason.

F-1983, F-1984: Add minimum + upper bounds to requirements/{prod,test,
docs}.txt so a hijacked release of cffi, tox, pytest, types-cffi,
Sphinx, or sphinx_rtd_theme does not get pulled silently on the next
pip install. setup.txt resolves transitively via prod.txt.
2026-05-12 13:15:35 +01:00
David Garske c6d23d30f4
Merge pull request #118 from LinuxJedi/f-fixes
Fenrir fixes
2026-05-11 10:27:11 -07:00
Andrew Hutchings 98215b60f6 Address Copilot concerns 2026-05-11 13:05:23 +01:00
Andrew Hutchings 57cca0e90d Validate raw element lengths in EccPublic/EccPrivate.decode_key_raw
wc_ecc_import_unsigned takes no length parameters for qx/qy/d: it
reads exactly curve_size bytes from each pointer based on curve_id,
via mp_read_unsigned_bin in wc_ecc_import_raw_private. The Python
decode_key_raw wrappers handed the user-supplied buffers straight
through without any length check, so a shorter buffer caused the C
library to read past the end of the Python buffer (OOB read of
adjacent memory, potentially leaking it into the imported key or
segfaulting). A longer buffer silently dropped the extra bytes.

Add wc_ecc_get_curve_size_from_id to the CFFI cdef, then in both
decode_key_raw methods t2b the inputs, look up the expected curve
size, and raise ValueError if any of qx/qy/d does not match. Reject
unknown curve_id values with a clear message rather than falling
through to wolfSSL with a bogus size.

Add test_ecc_decode_key_raw_rejects_wrong_length covering short qx,
long qy, short d, unknown curve_id, and the happy path on both
EccPublic and EccPrivate.

F-3088
2026-05-11 12:33:41 +01:00
Andrew Hutchings cd9cdeba5f Fix wc_ecc_import_unsigned cdef to match wolfSSL header
scripts/build_ffi.py declared qx, qy, and d as `byte*` while the
wolfSSL header (ecc.h) declares all three as `const byte*`. wolfSSL is
const-correct here and does not mutate the inputs, so there is no
observable bug today, but the non-const cdef let CFFI hand a writable
pointer into Python bytes storage on EccPublic.decode_key_raw and
EccPrivate.decode_key_raw calls. Update the cdef to match the header.

F-3087
2026-05-11 12:29:15 +01:00
Andrew Hutchings 000472761c Fix Ed448 ctx cdef to match wolfSSL header signature
scripts/build_ffi.py declared wc_ed448_sign_msg and wc_ed448_verify_msg
with two cdef discrepancies vs the wolfSSL header (ed448.h):

  - ctx was typed `byte*` instead of `const byte*`. CFFI was therefore
    happy to forward a writable pointer into Python bytes storage.
    The wolfSSL functions are const-correct and do not mutate ctx, so
    this had no runtime impact, but it widened the surface CFFI was
    willing to permit.

  - ctx_len was typed `word32` instead of `byte`. RFC 8032 caps Ed448
    context at 255 bytes, and wolfSSL's prototype reflects that with a
    1-byte parameter. The mismatch happens to work on x86_64 SysV
    because the low byte is what the callee reads, but it is still a
    real ABI discrepancy and would not be guaranteed on other
    platforms or calling conventions.

Update the cdef to const byte* / byte to match the header on both
functions. Add a guard in Ed448Public.verify and Ed448Private.sign so
callers passing a ctx longer than 255 bytes get a clear ValueError
rather than relying on CFFI's narrowing behavior.

ML-DSA's wc_dilithium_sign_ctx_msg / wc_dilithium_verify_ctx_msg cdefs
were also reviewed and already match the wolfSSL header.

F-3086
2026-05-11 12:27:23 +01:00
Andrew Hutchings e961e83656 Avoid passing Python bytes to non-const wc_GetPkcs8TraditionalOffset
wc_GetPkcs8TraditionalOffset is declared in the wolfSSL public header
as taking byte* input (non-const), even though the current
implementation only reads from the buffer via ToTraditionalInline_ex.
RsaPrivate.__init__ was passing a Python bytes object directly into
that non-const parameter on the PKCS#8 fallback path, which lets CFFI
hand the C library a writable pointer into immutable storage. There is
no observable mutation today, but the contract permits it, and any
future wolfSSL change to actually write through the parameter would
silently corrupt the caller's bytes object.

Copy the key into a CFFI-owned byte array for that one call. The
adjacent wc_RsaPrivateKeyDecode calls are unaffected since their cdef
is already const byte*. PKCS#8 key load is a one-time cost at
construction, so the extra allocation is negligible.

Not changing the cdef to const byte* because the wolfSSL public header
itself declares the parameter non-const; diverging from the header
would cause compile warnings in the CFFI-generated glue code. If
wolfSSL ever const-corrects the header upstream, this copy can be
dropped.

F-2664
2026-05-11 12:15:51 +01:00
Andrew Hutchings 09770093bd Fix const on `wc_RsaPSS_Verify` 2026-05-11 12:12:36 +01:00
Andrew Hutchings 5e01d07e7f Fix ChaCha._set_key wiping encrypt stream state on first decrypt
ChaCha._set_key ignored its `direction` argument and unconditionally
re-keyed both self._enc and self._dec whenever either was allocated.
Because _Cipher.encrypt and _Cipher.decrypt only call _set_key the
first time their respective context is allocated, doing
`encrypt(...); decrypt(...); encrypt(...)` on the same instance
silently rewound the encryption stream: the first decrypt() allocated
self._dec and re-keyed self._enc back to counter 0, so the second
encrypt() produced ciphertext as if starting from the beginning of the
keystream rather than continuing it. set_iv() relies on the
both-directions reset to change the IV, so that path must be preserved.

Honor the direction argument: direction _ENCRYPTION / _DECRYPTION only
touches the matching context, while direction 0 (the value set_iv
passes) keeps the existing reset-both behavior.

Add two regression tests: one that interleaves encrypt/decrypt/encrypt
and compares against a baseline two-encrypt sequence to catch any
future re-introduction of cross-direction state stomping, and one that
locks in set_iv's reset-both semantics so the fix is not later
narrowed in a way that breaks IV changes.

F-3586
2026-05-11 12:03:48 +01:00
Andrew Hutchings ce93174570 Fix Random.__init__ AttributeError on builds without ML-KEM/ML-DSA
Random.__init__ used _lib.INVALID_DEVID as a default parameter value,
but INVALID_DEVID is only declared in the CFFI cdef inside
`if features["ML_KEM"] or features["ML_DSA"]`. Since default parameters
are evaluated at module import time, any wolfSSL build that lacks both
ML-KEM and ML-DSA (e.g. via USE_LOCAL_WOLFSSL pointing at a custom
build) raises AttributeError on `import wolfcrypt.random`, cascading
into wolfcrypt.ciphers and effectively breaking the entire library.

Hardcode the default to -2, matching the convention already used by
_Hmac._init and AesGcmStream.__init__ (which call wc_HmacInit /
wc_AesInit with -2 directly rather than referencing _lib.INVALID_DEVID).

Add a build-no-pqc GitHub Actions job that builds wolfSSL with
--disable-kyber --disable-dilithium, installs wolfcrypt-py against it
via USE_LOCAL_WOLFSSL, and runs an import-smoke step plus the full
pytest suite. The smoke step is the explicit regression guard: it
imports wolfcrypt.random and instantiates Random(), which would fail
at import time if the default ever again references a CFFI symbol that
is only conditionally declared.

F-2659
2026-05-11 12:02:26 +01:00
Andrew Hutchings 6c1c1b76bb Fix AesSiv silently mangling associated data
AesSiv._prepare_associated_data only checked for str and bytes when
deciding whether the input was a single associated-data block, so
bytearray and memoryview fell through to the "list of blocks" branch.
Iterating those types yields integers, which t2b() then turned into
ASCII decimal byte-strings (b'16', b'17', ...), producing many bogus
blocks instead of one. The C SIV computation succeeded over wrong
associated data, so encryption/decryption silently produced an
incorrect tag rather than raising. This broke interoperability between
callers passing the same content as different buffer types.

Match the set of types accepted by t2b() by including bytearray and
memoryview in the isinstance check.

Add a parametrized test that reuses the OpenSSL KAT vectors with bytes,
bytearray, and memoryview wrappers; a round-trip test would not have
caught this since both sides mangle identically.

F-1981
2026-05-11 11:47:56 +01:00
David Garske 4ec45a6511
Merge pull request #110 from roberthdevries/special-wc-api-retval-exceptions
Raise specialized WolfCryptApiError for failed API calls.
2026-05-08 15:59:50 -07:00
Robert de Vries 2bcc7031bd
Revert change to raising WolfCryptError 2026-05-08 17:12:50 +02:00
Robert de Vries 8d80db4914
Pass error return value to exception
If the size return value is negative, an error is detected. In that case raise an exception. Even though a zero is not a valid size value, it would indicate success in other cases. But a 0 return value would not make much sense as a return value for this function.
2026-05-08 16:38:59 +02:00
David Garske 9c8f9fbfc0
Merge pull request #115 from roberthdevries/add-pyproject-toml
Convert python project configuration to pyproject.toml.
2026-05-07 16:23:30 -07:00
Robert de Vries ddf707b9b8
Merge branch 'master' into add-pyproject-toml 2026-05-06 00:51:03 +02:00
David Garske 23e9a7c52b
Merge pull request #117 from roberthdevries/simplify-feature-enable-variable-string
Simplify generating feature enabled variables using an f-string.
2026-05-05 11:20:13 -07:00
David Garske d34abdb012
Merge pull request #116 from roberthdevries/fix-bare-except-build-ffi
Use specific exception instead of bare except in build_ffi.py
2026-05-05 11:19:57 -07:00
David Garske e48fb07c43
Merge pull request #113 from roberthdevries/remove-redundant-stuff
Remove redundant parentheses and bytes() calls.
2026-05-05 11:16:44 -07:00
David Garske 87fbbe5b9f
Merge pull request #111 from roberthdevries/use-modern-f-strings
Use modern f-strings replacing str.format().
2026-05-05 11:16:40 -07:00
David Garske efe131ee96
Merge pull request #109 from kareem-wolfssl/gh108
Wrap _delete/_copy class attrs in staticmethod so self isn't bound as an extra arg.
2026-05-05 10:43:56 -07:00
David Garske 292557e057
Merge pull request #100 from roberthdevries/add-typing
Start adding typing information.
2026-05-05 10:40:52 -07:00
David Garske e7300e98bf
Merge pull request #107 from roberthdevries/export__wolfssl_version__
Add __wolfssl_version__ to exported symbols.
2026-05-05 10:40:29 -07:00
David Garske b0708870ba
Merge pull request #93 from roberthdevries/rsa-public-add-rng-param
Make the random generator of _Rsa and RsaPublic configurable.
2026-05-05 10:35:04 -07:00
David Garske c17f7f0401
Merge pull request #105 from roberthdevries/missing-definition-ML_DSA_KEYGEN_SEED_LENGTH
Add missing definition ML_DSA_KEYGEN_SEED_LENGTH.
2026-05-05 10:35:01 -07:00
David Garske a6668e0f08
Merge pull request #101 from roberthdevries/fix-passing-mutable-argument-as-default
Fix mutable arguments passed as default arguments.
2026-05-04 14:29:35 -07:00
Robert de Vries 3ae2756759 Fix errors in pyproject.toml sections for ruff.
Also add entry in ChangeLog mentioning that older Python versions
are no longer supported.
2026-04-28 20:22:25 +02:00
Robert de Vries 1723007785 Simplify generating feature enabled variables using an f-string. 2026-04-27 17:14:52 +02:00
Robert de Vries 0f61f5f771 Use specific exception instead of bare except in build_ffi.py
A bare except catches BaseException which includes KeyboardInterrupt,
SystemExit, Exception, and others.
Catching BaseException can make it hard to interrupt the program (e.g., with
Ctrl-C) and can disguise other problems.
2026-04-27 16:54:52 +02:00
Robert de Vries 4dbd4951ea Convert python project configuration to pyproject.toml.
Modern python projects standardize on pyproject.toml to reduce
the number of configuration files required for all tools.
2026-04-27 16:17:15 +02:00
Robert de Vries 17dad74a20 Remove redundant parentheses and bytes() calls. 2026-04-24 22:51:00 +02:00
Robert de Vries a60f8223fe Use modern f-strings replacing str.format().
f-strings have been introduced in Python 3.6.
2026-04-24 22:14:25 +02:00
Robert de Vries 0ac207d34a Raise specialized WolfCryptApiError for failed API calls.
This exception takes the return value and converts that to
a human-readable string (if error string support is compiled in.)

The specialized exception is derived from WolfCryptError meaning
that existing users will not notice the difference except for the
nicer description.
2026-04-24 22:01:02 +02:00
Kareem 8bd719c4a7 Add regression test. 2026-04-22 17:30:12 -07:00
Kareem f6c27bf55d Wrap _delete/_copy class attrs in staticmethod so self isn't bound as an extra arg.
Fixes #108.
2026-04-22 16:19:41 -07:00
Robert de Vries 61c7990be0 Addressed various review comments. 2026-04-20 22:37:07 +02:00