Skip to content

Minor bugfixes#10875

Merged
dgarske merged 9 commits into
wolfSSL:masterfrom
danielinux:fixes-2026-07-10
Jul 10, 2026
Merged

Minor bugfixes#10875
dgarske merged 9 commits into
wolfSSL:masterfrom
danielinux:fixes-2026-07-10

Conversation

@danielinux

@danielinux danielinux commented Jul 10, 2026

Copy link
Copy Markdown
Member

Description

A bunch of bugs surfaced during wolfcrypt mc-dc coverage campaign have been fixed.

curve25519 big-endian public-key validation.

600880a
wc_curve25519_check_public screens out weak/out-of-range X25519 public keys, and it has mirrored little-endian and big-endian code paths. The "order-1 or higher" boundary loop in the little-endian branch scans for middle bytes equal to 0xff (if (pub[i] != 0xff) break;), which is correct because the field prime p = 2²⁵⁵−19 is 0x7fff…ffed, its interior bytes are 0xff. The big-endian branch instead tested if (pub[i] != 0), so it broke out of the loop on the first non-zero byte and never actually detected the near-prime range. The fix changes that one operand to 0xff so big-endian callers get the same near-field-prime rejection as little-endian ones.

DSA import parameter error-gating.

30ceba0
In _DsaImportParamsRaw, each step (read p, primality-check p, read q, read g) is guarded by if (err == MP_OKAY), but the final (L,N) size check via CheckDsaLN ran unconditionally. So if p failed its primality check (err = DH_CHECK_PUB_E), execution still fell through to the size check, which read qSz from a q that was never actually parsed (its own read is gated on success), and unconditionally overwrote the specific DH_CHECK_PUB_E with a generic BAD_FUNC_ARG. The fix wraps the size check in the same if (err == MP_OKAY) guard, so the first and most specific error is preserved and no stale/unset q is measured.

Note: the associated hardcoded faulty test has been temporarily fixed in 8dcef49 until the final fixed test lands in #10876

curve25519_base prototype for strict-C builds

3aecf6f
On the CURVED25519_X64 (Intel x64 assembly) and aarch64 ARMASM paths, wc_curve25519_make_pub calls curve25519_base(pub, priv), but that function is provided only in assembly (fe_x25519_asm.S, armv8-curve25519) and had no C prototype in any header, unlike its sibling curve25519(), which is declared in fe_operations.h. A strict C compiler treating implicit function declarations as errors (e.g. clang 21 with -Werror=implicit-function-declaration) therefore failed to build that configuration. The fix adds WOLFSSL_LOCAL int curve25519_base(byte* q, const byte* n); next to the curve25519() prototype, guarded by the same config, so the assembly path compiles under strict C. I reproduced the exact config and confirmed the object now references the symbol.

RNG PollAndReSeed build guard.

666de7d
PollAndReSeed was compiled under #ifdef HAVE_HASHDRBG alone, but its only callers live in the !CUSTOM_RAND_GENERATE_BLOCK branch of wc_RNG_GenerateBlock, and it references wc_GenerateSeed, which isn't provided when a custom block generator replaces the seed layer. So defining HAVE_HASHDRBG together with CUSTOM_RAND_GENERATE_BLOCK compiled a function that referenced an undefined symbol, producing a link error. The fix narrows the guard to #if defined(HAVE_HASHDRBG) && !defined(CUSTOM_RAND_GENERATE_BLOCK) , matching how _InitRng already guards its DRBG code so the function is compiled exactly when it can be called.

RNG wc_GenerateSeed NULL-output check.

0a0e084
The Unix wc_GenerateSeed validated its os argument for NULL but not its output buffer, so a NULL output pointer passed straight into the entropy backend. glibc's vDSO-accelerated getrandom() dereferences the destination without validating it and segfaults rather than returning an error, so a NULL output crashed the process instead of failing cleanly. The fix adds output to the NULL check at the top of the function — mirroring the convention already used in wc_RNG_GenerateBlock so the seed API returns BAD_FUNC_ARG for a NULL buffer regardless of which entropy backend is active.

compile-time guard for small-vs-asm 25519.

9721c52
The small (reduced-C) curve25519/ed25519 code and the Intel x64 assembly both define the same fe_, sc_, and curve25519 symbols, so building both yields duplicate-symbol link errors. This happens with --enable-usersettings (which bypasses configure's implementation selection) when a user_settings.h keeps CURVE25519_SMALL/ED25519_SMALL while USE_INTEL_SPEEDUP enables the x64 asm. Rather than change the build system (broad blast radius, per your steer), the fix adds an #error in fe_operations.h keyed on CURVED25519_X64 && (CURVE25519_SMALL || ED25519_SMALL). CURVED25519_X64 being the single source of truth for "x64 25519 asm active", so the conflict fails fast with a clear message, with NO_CURVED25519_X64 as the documented escape hatch. I verified it stays silent on --enable-all (no false-positive) and fires on the incompatible combination.

deregister mem-zero entries in wc_FreeDhKey

cf5c126
wc_DhImportKeyPair() registers key->priv for zero-on-free tracking via mp_memzero_add() under WOLFSSL_CHECK_MEM_ZERO, but wc_FreeDhKey() cleared priv with mp_forcezero(), which zeroes the data without removing the registration. Unlike wc_FreeRsaKey(), wc_FreeDhKey() had no wc_MemZero_Check() to remove the entry, so the registration leaked past the DhKey's lifetime and a later, unrelated wc_MemZero_Check() over reused stack could false-abort on it. Add wc_MemZero_Check(key, sizeof(*key)) at the end of wc_FreeDhKey(), mirroring wc_FreeRsaKey().

zero wc_MakeRsaKey stack temporaries for mem-zero check

3fed5f9
wc_MakeRsaKey()'s non-small-stack path declares p/q/tmp1..3 as stack mp_ints and only mp_init's them after the argument and size checks. An early 'goto out' from those checks reaches the WOLFSSL_CHECK_MEM_ZERO cleanup, which calls mp_memzero_check() on the still-uninitialized structs; the garbage size field makes the check scan an arbitrary stack range and can false-abort on unrelated registered memory. Zero the temporaries up front (under WOLFSSL_CHECK_MEM_ZERO) so the early-out cleanup is safe.

Testing

mc-dc campaign phase 2 PR #10876

wc_curve25519_check_public's BIG_ENDIAN branch checked pub[i] != 0 in its
top-order boundary loop where the mirrored LITTLE_ENDIAN branch checks
pub[i] != 0xff. The field prime p = 2^255 - 19 has 0xff middle bytes, so
the != 0 test broke out on the first non-0xff byte and the near-prime
rejection was effectively non-functional for big-endian inputs. Match the
little-endian branch so out-of-range big-endian public keys are rejected.
The (L,N) size check ran unconditionally, so after an earlier failure it
overwrote the specific error (e.g. DH_CHECK_PUB_E from the p primality
check) with BAD_FUNC_ARG, and computed qSz from a q that was never read
(the q read is itself gated on err==MP_OKAY). Gate the size check the same
way as the surrounding steps so the first, most specific error is returned.
curve25519.c calls curve25519_base() on the CURVED25519_X64 / aarch64
ARMASM path, but the function is only defined in assembly and had no C
prototype in any header, so a strict C compiler (implicit-declaration as
error) failed to build that configuration. Declare it alongside the
sibling curve25519() prototype under the same guard.
PollAndReSeed was compiled under #ifdef HAVE_HASHDRBG alone, but its only
callers (in wc_RNG_GenerateBlock) sit in the #else of CUSTOM_RAND_GENERATE_
BLOCK, and it references wc_GenerateSeed which is not provided when a custom
block generator replaces the seed layer. Defining HAVE_HASHDRBG together
with CUSTOM_RAND_GENERATE_BLOCK therefore produced an undefined-symbol link
error. Match _InitRng's guard so the function is compiled exactly when it
can be called.
wc_GenerateSeed only checked os for NULL, so a NULL output passed straight
into the entropy backend. glibc's vDSO getrandom() dereferences the buffer
without validating it and segfaults instead of returning an error. Add the
output NULL check (matching wc_RNG_GenerateBlock's convention) so the public
seed API fails cleanly with BAD_FUNC_ARG.
The small (reduced-C) curve25519/ed25519 code and the Intel x64 assembly
both define the same fe_/sc_/curve25519 symbols. A user_settings.h that
keeps CURVE25519_SMALL/ED25519_SMALL while USE_INTEL_SPEEDUP selects the
x64 assembly (as happens with --enable-usersettings, which does not run
configure's implementation selection) links with duplicate symbols that
are hard to diagnose. Detect the incompatible combination at compile time
via a clear #error keyed on CURVED25519_X64 (the single source of truth
for 'x64 25519 asm active'), so it fails fast instead. NO_CURVED25519_X64
remains the escape hatch to keep the small implementation.
Copilot AI review requested due to automatic review settings July 10, 2026 06:45
@danielinux danielinux self-assigned this Jul 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses several correctness and build-configuration issues discovered during a wolfcrypt MC/DC coverage effort, improving key validation, error propagation, strict-C build compatibility, and RNG build guards.

Changes:

  • Fix big-endian Curve25519 public-key near-prime (“order-1 or higher”) screening to match the little-endian logic.
  • Preserve specific DSA import errors by gating the (L,N) size check on prior parse/validation success.
  • Add strict-C prototypes / compile-time guards to prevent implicit declarations and incompatible Curve25519 implementation combinations.
  • Tighten RNG reseed compilation guards and add a NULL output check to wc_GenerateSeed() to avoid backend faults.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
wolfssl/wolfcrypt/fe_operations.h Adds a compile-time incompatibility #error for SMALL vs x64 asm builds and declares curve25519_base() for strict-C configurations.
wolfcrypt/src/random.c Aligns PollAndReSeed build guard with callability and adds NULL-output validation to wc_GenerateSeed().
wolfcrypt/src/dsa.c Prevents CheckDsaLN from overwriting earlier, more-specific DSA import errors.
wolfcrypt/src/curve25519.c Corrects big-endian wc_curve25519_check_public() boundary scanning to properly detect near-prime values.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread wolfcrypt/src/curve25519.c
Comment thread wolfcrypt/src/dsa.c
wc_DhImportKeyPair() registers key->priv for zero-on-free tracking via
mp_memzero_add() under WOLFSSL_CHECK_MEM_ZERO, but wc_FreeDhKey() cleared
priv with mp_forcezero(), which zeroes the data without removing the
registration. Unlike wc_FreeRsaKey(), wc_FreeDhKey() had no
wc_MemZero_Check() to remove the entry, so the registration leaked past
the DhKey's lifetime and a later, unrelated wc_MemZero_Check() over reused
stack could false-abort on it. Add wc_MemZero_Check(key, sizeof(*key)) at
the end of wc_FreeDhKey(), mirroring wc_FreeRsaKey().

@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 #10875

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread wolfcrypt/src/rsa.c Outdated
wc_MakeRsaKey()'s non-small-stack path declares p/q/tmp1..3 as stack
mp_ints and only mp_init's them after the argument and size checks. An
early 'goto out' from those checks reaches the WOLFSSL_CHECK_MEM_ZERO
cleanup, which calls mp_memzero_check() on the still-uninitialized structs;
the garbage size field makes the check scan an arbitrary stack range and
can false-abort on unrelated registered memory. Zero the temporaries up
front (under WOLFSSL_CHECK_MEM_ZERO) so the early-out cleanup is safe.
@danielinux

Copy link
Copy Markdown
Member Author

Jenkins retest this please (one job timed out)

@dgarske dgarske merged commit 3538c4d into wolfSSL:master Jul 10, 2026
338 of 339 checks passed
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.

5 participants