Skip to content

Fix C challenge nonce CSPRNG handling#4864

Open
SimoneMariaRomeo wants to merge 1 commit into
Scottcjn:mainfrom
SimoneMariaRomeo:codex/c-challenge-secure-nonce
Open

Fix C challenge nonce CSPRNG handling#4864
SimoneMariaRomeo wants to merge 1 commit into
Scottcjn:mainfrom
SimoneMariaRomeo:codex/c-challenge-secure-nonce

Conversation

@SimoneMariaRomeo
Copy link
Copy Markdown

Summary

  • Replaces rand()/srand() challenge nonces with OS CSPRNG bytes: arc4random_buf() on macOS and a checked/retried getrandom() loop on Linux.
  • Fails closed when no supported OS CSPRNG is available, so challenge generation does not return a weak, partial, or uninitialized nonce.
  • Adds source-level regression coverage for the nonce source, checked Linux reads, unsupported-platform fallback, and fail-closed call site.

Fixes #4861.

Validation

  • python -m pytest tests\test_challenge_response_secure_nonce.py -q -> 4 passed
  • python -m py_compile tests\test_challenge_response_secure_nonce.py -> passed
  • git diff --check -- rips\rustchain-core\src\anti_spoof\challenge_response.c tests\test_challenge_response_secure_nonce.py -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> OK
  • gcc --version / clang --version -> unavailable in this Windows environment, so I could not compile the C file locally

@github-actions github-actions Bot added BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) tests Test suite changes size/M PR: 51-200 lines labels May 12, 2026
Copy link
Copy Markdown
Contributor

@godd-ctrl godd-ctrl left a comment

Choose a reason for hiding this comment

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

Approved current head f07fe188f7eb97111e24d114f6450141f48d5670.

This fixes the nonce-generation issue I flagged on the previous C challenge PR: Linux now loops until the full nonce buffer is filled, retries EINTR, fails closed on other getrandom failures, initializes the Challenge struct before use, and removes the weak timestamp/rand fallback. Unsupported platforms also fail closed rather than mixing predictable bytes.

Validation performed:

  • git diff --name-status origin/main...HEAD -> challenge_response.c modified, tests/test_challenge_response_secure_nonce.py added
  • git diff --check origin/main...HEAD -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> passed
  • python -m py_compile tests\test_challenge_response_secure_nonce.py -> passed
  • python -m pytest tests\test_challenge_response_secure_nonce.py -q -> 4 passed
  • rg confirmed rand/srand removal and getrandom/arc4random_buf secure nonce paths
  • gcc --version -> unavailable in this Windows environment, so I could not compile the C file locally

No blocking issues found in the reviewed diff.

Copy link
Copy Markdown

@saim256 saim256 left a comment

Choose a reason for hiding this comment

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

Approving current head f07fe18.

This is a focused fix for #4861 and closes the blocker I saw in the earlier C nonce attempt: Linux getrandom() is now checked in a retry loop, short reads advance by the returned byte count, EINTR is retried, unsupported platforms fail closed, and generate_challenge() zero-initializes the struct before failing rather than returning a weak or partially initialized nonce. The rand()/srand() nonce path is gone.

Validation performed:

  • python -m pytest tests\test_challenge_response_secure_nonce.py -q -> 4 passed
  • python -m py_compile tests\test_challenge_response_secure_nonce.py -> passed
  • python tools\bcos_spdx_check.py --base-ref origin/main -> BCOS SPDX check: OK
  • git diff --check origin/main...HEAD -- rips/rustchain-core/src/anti_spoof/challenge_response.c tests/test_challenge_response_secure_nonce.py -> passed
  • where.exe gcc and where.exe clang -> no compiler installed locally, so I could not build the C file in this environment

Copy link
Copy Markdown

@dazer1234 dazer1234 left a comment

Choose a reason for hiding this comment

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

Code review for RustChain bounty #73.

Summary: This is a focused CSPRNG replacement for challenge nonces. The Linux path loops until the full nonce buffer is filled, retries EINTR, and the Apple path uses arc4random_buf; the tests also explicitly prevent rand()/srand() from returning.

Findings: No blocking issues found. The fail-closed path for unsupported platforms is appropriate for a security-sensitive nonce generator.

Verdict: Looks good.

Reviewed with OpenAI Codex assistance.

Copy link
Copy Markdown

@loganoe loganoe left a comment

Choose a reason for hiding this comment

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

Review for Scottcjn/rustchain-bounties#73. Approved current head f07fe1850e26010c400dfa31dec098a375dac9fe.

I focused on the Linux C build path that prior reviews could not exercise locally. The secure nonce helper uses getrandom() in a short-read loop, advances by the returned byte count, retries EINTR, and fails closed on unsupported platforms. generate_challenge() zero-initializes the struct before calling the helper and exits before returning a challenge when nonce generation fails.

Validation performed:

  • gcc -O0 rips/rustchain-core/src/anti_spoof/challenge_response.c -o /tmp/challenge_response_linux -> passed on Linux
  • gcc -std=gnu11 -Wall -Wextra -c rips/rustchain-core/src/anti_spoof/challenge_response.c -o /tmp/challenge_response_gnu.o -> passed with only pre-existing unused-variable/parameter warnings
  • PYTEST_DISABLE_PLUGIN_AUTOLOAD=1 uv run --no-project --with pytest --with flask python -m pytest tests/test_challenge_response_secure_nonce.py -q -> 4 passed
  • git diff --check origin/main...HEAD -> passed
  • python3 tools/bcos_spdx_check.py --base-ref origin/main -> OK

No blocking findings from the Linux compile/test pass.

@508704820
Copy link
Copy Markdown
Contributor

Code Review: Fix C challenge nonce CSPRNG handling

Summary

This PR replaces the insecure rand()/srand()-based nonce generation in challenge_response.c with proper CSPRNG calls (arc4random_buf on macOS, getrandom on Linux). Also removes the srand() call entirely. This is a critical security fix (see my bug report #4861 which identifies the same vulnerability).

Positive Observations ✅

  1. Platform-appropriate CSPRNG: arc4random_buf on macOS, getrandom on Linux — both are correct choices
  2. Proper EINTR handling: The getrandom loop correctly retries on EINTR
  3. memset(&c, 0, sizeof(c)): Zero-initializes the Challenge struct — prevents stack data leakage
  4. Removed srand(): The PRNG seed is no longer predictable
  5. Error handling: Fails loudly with exit(EXIT_FAILURE) if nonce generation fails
  6. Clean abstraction: fill_secure_nonce() function is well-structured

Issues Found 🔍

1. No fallback for non-Apple, non-Linux platforms (MEDIUM)

The function returns -1 for platforms other than macOS and Linux. This means:

  • FreeBSD, NetBSD, OpenBSD will fail at runtime
  • Windows (MinGW/MSVC) will fail
  • These platforms DO have CSPRNGs (arc4random_buf on BSD, BCryptGenRandom on Windows)

Recommendation: Add BSD and Windows support:

#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
    arc4random_buf(nonce, len);
    return 0;
#elif defined(_WIN32)
    return BCryptGenRandom(NULL, nonce, len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0 ? 0 : -1;

2. exit(EXIT_FAILURE) is harsh for a library function (LOW)

In a production system, crashing the entire process because of a nonce failure is extreme. Consider returning an error code and letting the caller decide. However, for the current standalone binary, this is acceptable.

3. Removed srand() but rand() still used elsewhere? (INFO)

If any other code in the C module still uses rand(), removing srand() means it uses the default seed (1). Check if rand() is used elsewhere and also needs replacement.

Verdict

Excellent security fix. The approach is correct and the implementation is clean. After adding BSD/Windows fallbacks (or at minimum documenting the platform limitation), this is ready to merge.

This is essentially the fix for bug #4861 that I filed — great to see it being addressed!

Review quality: Security-focused review with actionable feedback

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

Copy link
Copy Markdown
Contributor

@jaxint jaxint left a comment

Choose a reason for hiding this comment

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

Great contribution! LGTM.

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

Labels

BCOS-L1 Beacon Certified Open Source tier BCOS-L1 (required for non-doc PRs) size/M PR: 51-200 lines tests Test suite changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: challenge_response.c uses predictable rand()/srand() for nonce generation

7 participants