Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions .github/workflows/ti-c2000-compile.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
name: "CHAR_BIT != 8 (wide byte) guards"

# Guards for the CHAR_BIT != 8 (WOLFSSL_WIDE_BYTE) support added for the TI
# C2000 C28x, where a char is a 16-bit cell. Three independent jobs:
# C2000 C28x, where a char is a 16-bit cell. Independent jobs:
#
# ti_c2000_compile cl2000 compile-only over the C28x wolfCrypt subset.
# Needs the TI CGT, so it self-skips when that is not
# configured (see the job's env block).
# sha3_split64_host x86-64 build + wolfCrypt KAT run with WC_SHA3_SPLIT64
# forced. Always runs.
# noisesrc_host x86-64 build + make check of the generic noise source
# the C2000 entropy port sits on. Always runs.
# wide_byte_be_compile x86-64 syntax-only check of WOLFSSL_WIDE_BYTE combined
# with BIG_ENDIAN_ORDER. Always runs.
#
# Only the first job involves TI tooling or the C28x at all; the other two are
# Only the first job involves TI tooling or the C28x at all; the others are
# plain host jobs covering code paths this port introduced. On-target
# run-tests live on a hardware-in-the-loop runner (there is no public C28x
# simulator).
Expand All @@ -26,6 +28,7 @@ on:
- 'wolfcrypt/src/**'
- 'wolfssl/wolfcrypt/**'
- 'IDE/C2000/**'
- 'configure.ac'
- '.github/workflows/ti-c2000-compile.yml'
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
Expand All @@ -34,6 +37,7 @@ on:
- 'wolfcrypt/src/**'
- 'wolfssl/wolfcrypt/**'
- 'IDE/C2000/**'
- 'configure.ac'
- '.github/workflows/ti-c2000-compile.yml'

concurrency:
Expand Down Expand Up @@ -145,6 +149,30 @@ jobs:
make
./wolfcrypt/test/testwolfcrypt

# WHAT: x86-64 build + make check with --enable-noisesrc, which
# runs noisesrc_test: synthetic sources driving the RCT, APT, startup
# rerun, sampler-error and self-test paths, plus SHA3-256 KATs.
# NOT: nothing TI-specific and no hardware or TI CGT needed, so like the
# job above this always runs. The DCC sampler itself is not built.
# WHY: the wc_NoiseSrc_* layer is the C2000 port's whole health-test and
# conditioning path but is pure C, so its failure handling can be
# exercised on any host instead of only on hardware CI cannot reach.
noisesrc_host:
name: Noise source host test
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }}
runs-on: ubuntu-22.04
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
name: Checkout wolfSSL

- name: Build + make check with --enable-noisesrc
run: |
./autogen.sh
./configure --enable-noisesrc --enable-all
make
make check

# WHAT: gcc -fsyntax-only -Werror over the octet paths with both
# WOLFSSL_WIDE_BYTE and BIG_ENDIAN_ORDER defined. A pure compile
# smoke test: it only catches "that arm does not compile".
Expand Down
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1851,6 +1851,15 @@ if(WOLFSSL_CSHAKE)
override_cache(WOLFSSL_SHAKE256 "yes")
endif()

# Generic SP800-90B noise source (wc_NoiseSrc_*); conditions with SHA3-256
add_option("WOLFSSL_NOISESRC"
"Enable the generic SP800-90B noise source layer (default: disabled)"
"no" "yes;no")
if(WOLFSSL_NOISESRC)
override_cache(WOLFSSL_SHA3 "yes")
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_NOISE_SRC")
endif()

# SHA512
add_option("WOLFSSL_SHA512"
"Enable wolfSSL SHA-512 support (default: enabled)"
Expand Down
60 changes: 29 additions & 31 deletions IDE/C2000/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ turns that into an entropy source: a DCC counts PLLRAWCLK edges inside a
window of INTOSC cycles, and the **LSB of that count** is one noise bit,
carrying the relative phase drift of two physically distinct oscillators. Raw
noise is oversampled far past its measured min-entropy, health-tested per
SP800-90B 4.4, conditioned with SHA-256, and handed to the SP800-90A
SP800-90B 4.4, conditioned with SHA3-256, and handed to the SP800-90A
Hash-DRBG.

The work is split in two. The port file owns only the hardware -- DCC setup,
Expand Down Expand Up @@ -323,68 +323,66 @@ The hardware-selection group is what to reach for if the board already uses a DC
### The generic `wc_NoiseSrc_*` layer

None of the SP800-90B machinery is C2000-specific, so it lives in
`wolfcrypt/src/random.c` behind `WOLFSSL_NOISE_SRC` (declarations in
`wolfssl/wolfcrypt/random.h`) and this port configures it. A port that has a
raw noise source but no TRNG supplies one callback:
`wolfcrypt/src/rng_noisesrc.c` behind `WOLFSSL_NOISE_SRC` (declarations in
`wolfssl/wolfcrypt/rng_noisesrc.h`), outside the FIPS module boundary, and this
port configures it. It follows wolfEntropy's SP800-90B health-test and
failure semantics and conditions with SHA3-256, so it turns `WOLFSSL_SHA3`
on. A port that has a raw noise source but no TRNG supplies one callback:

```c
int my_sample(void* ctx, int srcIdx, byte* octet);
```

fills a `wc_NoiseSrc` with the callback, a domain-separation tag, a
caller-owned work buffer, the entropy budget (`hmin`, `margin`) and the
health-test cutoffs, and gets back:
health-test cutoffs -- any of those left zero selects wolfEntropy's defaults --
and gets back:

| Call | Does |
|---|---|
| `wc_NoiseSrc_Init` | Validates the config, derives the gather size, runs the SP800-90B 4.3 startup test |
| `wc_NoiseSrc_GenerateSeed` | Gathers, health-tests, SHA-256 conditions, wipes the output on any failure |
| `wc_NoiseSrc_GenerateSeed` | Gathers, health-tests, SHA3-256 conditions, wipes the output on any failure |
| `wc_NoiseSrc_GetRaw` | Unconditioned noise for characterization only |
| `wc_NoiseSrc_SelfTest` | Liveness: gathers must differ and must not be a constant octet |
| `wc_NoiseSrc_Free` | Zeroes state and clears the latched failure |
| `wc_NoiseSrc_Free` | Zeroes state and resets the health-test state |

`WC_NOISE_RAW_PER_SRC(hmin, margin)` sizes the work buffer from the entropy
budget so the port does not duplicate the formula. Source 0 is the credited
one; any further source is hashed in as defence in depth and is not budgeted.
The layer takes no locks -- the instance is caller-owned state, so a port that
shares one across threads provides its own mutual exclusion.
`WOLFSSL_C2000_ENTROPY` turns `WOLFSSL_NOISE_SRC` on implicitly.
`WOLFSSL_C2000_ENTROPY` turns `WOLFSSL_NOISE_SRC` on implicitly. Each source
carries its own health-test state, about 0.8 KW of `.bss` on the C28x.

### Health tests

SP800-90B 4.4.1 Repetition Count and 4.4.2 Adaptive Proportion run
continuously over every octet drawn from each source, with a startup test over
a full gather before anything is released. Cutoffs are derived for 4 bits of
min-entropy per octet at alpha = 2^-30 and are overridable. A failure returns
`ENTROPY_RT_E` / `ENTROPY_APT_E` and **no seed material is produced** -- the
source fails closed rather than degrading silently, and the failure is latched
until `wc_NoiseSrc_Free()`, because a source that trips and then passes is
exactly what continuous testing exists to catch.

Latching applies to the **credited** source only. Source 0 carries the entire
entropy budget, so its failure denies output. Sources 1 and up are unaccounted
extra hash input, and the cutoffs are derived for source 0's assumed
min-entropy rather than theirs, so one of them tripping is not evidence the
seed is weak: it is dropped for the life of the instance and stops
contributing. Output stays fully seeded because the budget never counted it,
and a source the budget ignores cannot deny service. On this part that means a
failing INTOSC2 degrades the source to INTOSC1 alone -- exactly the
`WOLFSSL_C2000_ENTROPY_NUM_SRC 1` configuration -- instead of killing the RNG.
`STARTUP_OCTETS` per source before anything is released. The APT uses a
sliding 512-sample window. Cutoffs are derived for 4 bits of min-entropy per
octet at alpha = 2^-30 and are overridable.

A failure on any source returns `ENTROPY_RT_E` / `ENTROPY_APT_E` and **no seed
material is produced**. The failing source's test state is reset, so the next
call reruns its startup test (~210 ms per source at the defaults) before
anything is released again; a source that stays broken fails every call. This
is the same reset-and-retry handling wolfEntropy uses. It applies to the
uncredited source too, so a failing INTOSC2 fails the call even though the
budget never counted it. If INTOSC2 proves marginal on a board, build with
`WOLFSSL_C2000_ENTROPY_NUM_SRC 1`.

Because those paths only fire on genuinely broken hardware, `noisesrc_test()`
in `wolfcrypt/test/test.c` drives them with synthetic sources -- stuck, biased,
sampler-error, and periodic -- on the host:

```sh
./configure --enable-all CFLAGS="-DWOLFSSL_NOISE_SRC" && make check
./configure --enable-noisesrc --enable-all && make check
```

Note `wolfentropy.c`'s `HAVE_ENTROPY_MEMUSE` is *not* a usable substitute
here: its noise is memory-access timing jitter, which presumes a cache, and
the C28x is in-order and cacheless with deterministic RAM timing. Its default
state array is also ~256 KW on this target against ~100 KW of RAM. Its health
tests are `static` and hardcoded to 1 bit of min-entropy per sample, so they
are not reusable at this source's cutoffs either.
Note wolfEntropy's MemUse source (`HAVE_ENTROPY_MEMUSE`) is *not* a usable
substitute here: its noise is memory-access timing jitter, which presumes a
cache, and the C28x is in-order and cacheless with deterministic RAM timing.
Its default state array is also ~256 KW on this target against ~100 KW of RAM.

## Enabling on your build

Expand Down
29 changes: 16 additions & 13 deletions IDE/C2000/compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,24 @@ for s in $SRCS; do
fi
done

# random.c again with the entropy gate on: that turns WOLFSSL_NOISE_SRC on and
# pulls in the generic SP800-90B noise-source layer, which is otherwise left
# rng_noisesrc.c and random.c again with the entropy gate on: that turns
# WOLFSSL_NOISE_SRC on, compiling the generic SP800-90B noise-source layer in
# rng_noisesrc.c and the C2000 wc_GenerateSeed() branch in random.c, both left
# out of the sweep above. Needs no C2000Ware - only the port .c touches
# driverlib.
printf 'CC random.c (WOLFSSL_C2000_ENTROPY) ... '
if "$CL" $CFLAGS $INCS --define=WOLFSSL_C2000_ENTROPY \
--compile_only --skip_assembler \
--asm_directory="$OUT" --obj_directory="$OUT" \
"$WOLFROOT/wolfcrypt/src/random.c" > "$OUT/random-noise.log" 2>&1; then
echo "ok"
else
echo "FAIL"
cat "$OUT/random-noise.log"
rc=1
fi
for s in rng_noisesrc random; do
printf 'CC %s.c (WOLFSSL_C2000_ENTROPY) ... ' "$s"
if "$CL" $CFLAGS $INCS --define=WOLFSSL_C2000_ENTROPY \
--compile_only --skip_assembler \
--asm_directory="$OUT" --obj_directory="$OUT" \
"$WOLFROOT/wolfcrypt/src/$s.c" > "$OUT/$s-noise.log" 2>&1; then
echo "ok"
else
echo "FAIL"
cat "$OUT/$s-noise.log"
rc=1
fi
done

# The AESA hardware-AES port needs C2000Ware driverlib headers, which CI does
# not download, so it is an opt-in extra leg: set C2000WARE to a C2000Ware
Expand Down
7 changes: 7 additions & 0 deletions cmake/functions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,9 @@ function(generate_build_flags)
if(WOLFSSL_RNG_BANK OR WOLFSSL_USER_SETTINGS)
set(BUILD_RNG_BANK "yes" PARENT_SCOPE)
endif()
if(WOLFSSL_NOISESRC OR WOLFSSL_USER_SETTINGS)
set(BUILD_NOISESRC "yes" PARENT_SCOPE)
endif()
set(USE_VALGRIND ${WOLFSSL_VALGRIND})
if(WOLFSSL_MD4 OR WOLFSSL_USER_SETTINGS)
set(BUILD_MD4 "yes" PARENT_SCOPE)
Expand Down Expand Up @@ -1391,6 +1394,10 @@ function(generate_lib_src_list LIB_SOURCES)
list(APPEND LIB_SOURCES wolfcrypt/src/rng_bank.c)
endif()

if(BUILD_NOISESRC)
list(APPEND LIB_SOURCES wolfcrypt/src/rng_noisesrc.c)
endif()

if(BUILD_AFALG)
list(APPEND LIB_SOURCES wolfcrypt/src/port/af_alg/wc_afalg.c)
endif()
Expand Down
2 changes: 2 additions & 0 deletions cmake/options.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,8 @@ extern "C" {
#cmakedefine FP_ECC
#undef HAVE_WC_RNG_BANK
#cmakedefine HAVE_WC_RNG_BANK
#undef WOLFSSL_NOISE_SRC
#cmakedefine WOLFSSL_NOISE_SRC
#undef WC_RNG_WANT_BANKREF_SUPPORT
#cmakedefine WC_RNG_WANT_BANKREF_SUPPORT
#undef WC_RNG_NO_AUTO_LOCK
Expand Down
20 changes: 20 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -7761,6 +7761,14 @@ AC_ARG_ENABLE([entropy-memuse],
[ ENABLED_ENTROPY_MEMUSE=$enableval ]
)

# Generic SP800-90B noise source (wc_NoiseSrc_*) for ports with a raw physical
# noise source, e.g. the TI C2000 DCC entropy port
AC_ARG_ENABLE([noisesrc],
[AS_HELP_STRING([--enable-noisesrc],[Enable the generic SP800-90B noise source layer (default: disabled)])],
[ ENABLED_NOISESRC=$enableval ],
[ ENABLED_NOISESRC=no ]
)

# AES key wrap
# Accepts a comma-separated value list; "padding" adds RFC 5649 key wrap with
# padding on top of the base RFC 3394 key wrap.
Expand Down Expand Up @@ -8918,6 +8926,11 @@ then
ENABLED_SHAKE128=yes
ENABLED_SHAKE256=yes
fi
# The noise source conditions with SHA3-256.
if test "$ENABLED_NOISESRC" != "no"
then
ENABLED_SHA3=yes
fi
# Falcon uses SHA-3 / SHAKE256 for hash-to-point.
if test "$ENABLED_FALCON" != "no"
then
Expand Down Expand Up @@ -9581,6 +9594,11 @@ then
esac
fi

if test "$ENABLED_NOISESRC" != "no"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NOISE_SRC"
fi

if (test "$ENABLED_RNG" = "yes" && test "$ENABLED_ENTROPY_MEMUSE" != "no") || test "$ENABLED_BENCHMARK" = "yes"
then
AC_SEARCH_LIBS([clock_gettime],[rt])
Expand Down Expand Up @@ -14625,6 +14643,7 @@ AM_CONDITIONAL([BUILD_ECCSI],[test "x$ENABLED_ECCSI" = "xyes" || test "x$ENABLED
AM_CONDITIONAL([BUILD_SAKKE],[test "x$ENABLED_SAKKE" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_MEMORY],[test "x$ENABLED_MEMORY" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_MEMUSE],[test "x$ENABLED_ENTROPY_MEMUSE" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_NOISESRC],[test "x$ENABLED_NOISESRC" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_RNG_BANK],[test "$ENABLED_RNG_BANK" = "yes" || test "$ENABLED_USERSETTINGS" = "yes"])
AM_CONDITIONAL([BUILD_RSA],[test "x$ENABLED_RSA" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
AM_CONDITIONAL([BUILD_DH],[test "x$ENABLED_DH" != "xno" || test "x$ENABLED_USERSETTINGS" = "xyes"])
Expand Down Expand Up @@ -15189,6 +15208,7 @@ echo " * RNG lock on by default: $ENABLED_RNG_AUTOLOCK_DEFAULT"
echo " * RNG fork handlers: $ENABLED_RNG_AUTOFORK"
echo " * MmemUse Entropy:"
echo " * (AKA: wolfEntropy): $ENABLED_ENTROPY_MEMUSE"
echo " * Noise source: $ENABLED_NOISESRC"
echo " * PWDBASED: $ENABLED_PWDBASED"
echo " * Encrypted keys: $ENABLED_ENCKEYS"
echo " * scrypt: $ENABLED_SCRYPT"
Expand Down
Loading
Loading