Skip to content

SP 800-90B verdict preservation & APT/RCT compliance fixes - #11506

Merged
douzzer merged 15 commits into
wolfSSL:masterfrom
kaleb-himes:PQ-FS-2026-Part3-SecurityReview-nofallback-T
Oct 2, 2026
Merged

douzzer merged 15 commits into
wolfSSL:masterfrom
kaleb-himes:PQ-FS-2026-Part3-SecurityReview-nofallback-T

Conversation

@kaleb-himes

@kaleb-himes kaleb-himes commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

Description

What it does

  • Preserves SP 800-90B verdicts (ENTROPY_RT_E / ENTROPY_APT_E) through reseed instead of flattening them to RNG_FAILURE_E; instantiate already did this. Fixes a defect where a stuck source reported -294 at instantiate but -199 at reseed.

  • Fixes the APT: the cutoff was fixed at 325 for every window, unreachable in the 132-byte reseed and 196-byte instantiate seeds, so both APT loops were dead code. Cutoff is now per window size (101 at 132, 140 at 196, 325 at 512), satisfying IG D.K Res 16 (C ≤ W).

  • Replaces the sliding all-symbols scan with the literal SP 800-90B 4.4.2 test: reference sample, non-overlapping windows, cutoff derived for that test.

  • Re-adds all-values coverage as a 4.3 Req 1c additional developer-defined test, with its own derived cutoff at alpha/256 (union bound over the alphabet: 105 / 146 / 334). Implemented as a majority vote, so no histogram, no allocation, nothing to zeroize.

  • Short trailing windows slide back to full length; no window is formed when its cutoff could not be reached.

  • linuxkm: the DRBG reinit-and-retry path now treats a seed health-test alarm as recoverable, alongside RNG_FAILURE_E. DRBG_CONT_FIPS_E is deliberately excluded (catastrophic, must not retry).

  • In wc_linuxkm_drbg_generate()'s loop, when wc_RNG_GenerateBlock() returns one of the three codes, the kernel does not ignore the failure and retry the same state. It:

  • breaks out if any bytes were already delivered (if (slen > 0) break;), so a partially served request never gets a second, differently-seeded half;

  • retries at most three times (retried flag), then breaks to -EIO;

  • only retries when it may block (can_wait);

  • recovers by calling wc_rng_bank_inst_reinit(), which frees and re-instantiates the instance, i.e. a fresh wc_InitRng with fresh entropy, not a resumption of the condemned state.

How it maps to the standards

  • SP 800-90B §4.3 Req 2 is the controlling text: "the application is allowed to react differently to different types of failures (e.g., by inhibiting output for a short time)", provided the developer shows the failures handled that way are "extremely likely to be intermittent" and that a permanent failure "will ultimately signal an error condition to the consuming application and cease operation." One bounded retry into a fresh instantiation is exactly that shape: a stuck source fails the second attempt too, and the kernel then returns -EIO.
  • The evidence half of Req 2 is what all the measurement was for: zero alarms in 4·10^9 live instantiates and 10^9-scale seed sweeps, against an analytic per-window rate of 2^-30 by construction and ~2^-700 on real conditioned bytes. A single alarm is overwhelmingly likely to be a genuine source event rather than noise, and either way the retry cannot mask it for long, because a persistent fault fails twice.
  • DRBG_CONT_FIPS_E (-209) is a different animal. It comes from wc_RNG_HealthTestLocal(), the SP 800-90A §11.3 DRBG known-answer test, and §11.4.2 treats that as catastrophic: error state, no output, and recovery only by restart. fips.c enforces that, keying SetConTestFailure() and the move to FIPS_MODE_FAILED off exactly that code. Retrying it would be retrying a broken DRBG, so it is deliberately absent from the recovery condition and falls straight through to -EIO.

Testing

How it was tested

  • False positives, zero in every run: 4,000,000,000 live FIPS instantiates, 10,000,000 live reseeds, and 3.5·10^9 seed-level trials at 132, 196 and 600 bytes.
  • Detection improved at W=132: 0.47% → 52.6% at 76% bias, 2.1% → 88.1% at 80%.
  • Differential tested against an independently written model (histogram vs majority vote): 10M+ cases, 0 mismatches.
  • Negative controls: both tests proven load-bearing by mutants that disable each one (RCT disabled → 3 vectors fail; APT disabled → 4 fail), and each unit test fails when its expected cutoff is perturbed.
  • Bench: 8/8 cells on the pushed commit (fips-ready, fips-v7, debug-memory-all, linuxkm-host, c89-decls, c89-clang-unreachable, unknown-macros, check-source-text-macros), plus valgrind 0 errors and make-dist.
  • Cutoff tables generated by exact rational arithmetic; the generator reproduces the standard's published C=325 at W=512 before emitting.

Checklist

  • added tests
  • updated/added doxygen
  • updated appropriate READMEs
  • Updated manual and documentation

Note to self:

Security Policy needs two lines: H=1 is a deliberate floor, and the per-seed alpha is 2^-29 (two tests over one window).

@kaleb-himes kaleb-himes self-assigned this Sep 20, 2026
@github-actions

github-actions Bot commented Sep 20, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report

gcc-arm-cortex-m0plus

  • FLASH: .text +168 B (+1.8%, 69,123 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m3

  • FLASH: .text +140 B (+0.9%, 129,089 B / 262,144 B, total: 49% used)

gcc-arm-cortex-m4

  • FLASH: .text +128 B (+0.6%, 207,788 B / 262,144 B, total: 79% used)

gcc-arm-cortex-m4-baremetal

  • FLASH: .text +128 B (+1.6%, 71,523 B / 262,144 B, total: 27% used)

gcc-arm-cortex-m4-crypto-only

  • FLASH: .text +192 B (+0.7%, 180,829 B / 262,144 B, total: 69% used)

gcc-arm-cortex-m4-dtls13

  • FLASH: .rodata +1,024 B, .text +256 B (+0.7%, 192,260 B / 1,048,576 B, total: 18% used)

gcc-arm-cortex-m4-min-ecc

  • FLASH: .text +128 B (+1.8%, 66,309 B / 262,144 B, total: 25% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .rodata +1,024 B, .text +256 B (+0.2%, 790,300 B / 1,048,576 B, total: 75% used)

gcc-arm-cortex-m4-pkcs7

  • FLASH: .text +128 B (+0.5%, 220,894 B / 262,144 B, total: 84% used)

gcc-arm-cortex-m4-pq

  • FLASH: .rodata +1,024 B, .text +256 B (+0.4%, 308,208 B / 1,048,576 B, total: 29% used)

gcc-arm-cortex-m4-rsa-only

  • FLASH: .rodata +1,024 B, .text +192 B (+0.4%, 338,352 B / 1,048,576 B, total: 32% used)

gcc-arm-cortex-m4-sp-math

  • FLASH: .text +128 B (+1.8%, 66,309 B / 262,144 B, total: 25% used)

gcc-arm-cortex-m4-tls12

  • FLASH: .text +128 B (+0.9%, 129,853 B / 262,144 B, total: 50% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .text +192 B (+0.5%, 247,134 B / 262,144 B, total: 94% used)

gcc-arm-cortex-m7

  • FLASH: .text +128 B (+0.6%, 207,788 B / 262,144 B, total: 79% used)

gcc-arm-cortex-m7-pq

  • FLASH: .rodata +1,024 B, .text +192 B (+0.4%, 309,104 B / 1,048,576 B, total: 29% used)

gcc-arm-cortex-m7-tls13

  • FLASH: .text +256 B (+0.5%, 247,198 B / 262,144 B, total: 94% used)

linuxkm-pie

  • Data: __patchable_function_entries +64 B (+0.2%, 28,568 B)

linuxkm-standard

  • Data: __patchable_function_entries +40 B (+0.1%, 51,368 B)

stm32-sim-stm32h753

  • FLASH: .text +1,856 B (+1.0%, 194,964 B / 2,097,152 B, total: 9% used)

@kaleb-himes
kaleb-himes force-pushed the PQ-FS-2026-Part3-SecurityReview-nofallback-T branch 2 times, most recently from 5a1cf1d to ee78b06 Compare September 24, 2026 16:48
@kaleb-himes kaleb-himes added the For FIPS v7 Module Related to FIPS v7.0.0 module prep for submission label Sep 29, 2026
Copilot AI balanced review requested due to automatic review settings September 30, 2026 19:24
@kaleb-himes
kaleb-himes force-pushed the PQ-FS-2026-Part3-SecurityReview-nofallback-T branch from 20d09d6 to 6453a9a Compare September 30, 2026 19:24

This comment was marked as low quality.

@kaleb-himes
kaleb-himes force-pushed the PQ-FS-2026-Part3-SecurityReview-nofallback-T branch from 6453a9a to c997468 Compare October 1, 2026 19:18
@philljj
philljj requested a review from douzzer October 2, 2026 14:04
douzzer
douzzer previously requested changes Oct 2, 2026
Comment thread wolfcrypt/src/random.c Outdated
@douzzer douzzer removed their assignment Oct 2, 2026
@kaleb-himes
kaleb-himes requested a review from douzzer October 2, 2026 17:21
@kaleb-himes kaleb-himes removed their assignment Oct 2, 2026
@kaleb-himes
kaleb-himes dismissed douzzer’s stale review October 2, 2026 17:33

Requesting a re-review of the early condemnation.

@padelsbach

Copy link
Copy Markdown
Contributor

jenkins retest this please

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

tested with

wolfssl-multi-test.sh ...
quantum-safe-wolfssl-all-crypto-only-intelasm-sp-asm-fips-dev-linuxkm-next-clang-tidy
quantum-safe-wolfssl-all-crypto-only-intelasm-sp-asm-sp-fips-dev-linuxkm-mainline-insmod
quantum-safe-wolfssl-all-crypto-only-intelasm-sp-asm-fips-dev-linuxkm-next-insmod

Comment thread wolfcrypt/src/random.c
@douzzer
douzzer merged commit cad8c56 into wolfSSL:master Oct 2, 2026
393 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For FIPS v7 Module Related to FIPS v7.0.0 module prep for submission

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants