Add ML-DSA signing and verification for CMS/PKCS#7 SignedData, following
RFC 9882. ML-DSA is used in CMS "pure" mode: the signature is computed
over the complete message (the DER SET OF signed attributes, or the
eContent when none are present) with an empty context string and absent
signatureAlgorithm parameters, rather than over a pre-computed DigestInfo
as with RSA/ECDSA.
wolfcrypt/src/pkcs7.c:
- New ML-DSA helpers: wc_PKCS7_MlDsaLevelFromOID, wc_PKCS7_BuildPureSigMessage,
wc_PKCS7_MlDsaSign and wc_PKCS7_MlDsaVerify, wired into the per-algorithm
switch sites (GetSignSize, SignedDataGetEncAlgoId, SetPublicKeyOID,
CheckPublicKeyDer) and the sign/verify dispatchers. Only the final FIPS 204
ML-DSA OIDs are accepted; pre-standard draft Dilithium OIDs are not.
- GetSignSize derives the ML-DSA signature length from the parameter set.
- InitWithCert copies the signer public key into the RSA-sized publicKey buffer
only for RSA/ECC certs (the raw-sign callback consumers); large PQC keys such
as ML-DSA would overflow it and are never read back, so publicKeySz stays 0.
- wc_MlDsaKey is always heap allocated (it embeds multi-KB key buffers); the
accompanying DecodedCert uses the WC_DECLARE_VAR/WC_ALLOC_VAR_EX macros for
stack-vs-heap handling under WOLFSSL_SMALL_STACK.
- wc_PKCS7_SignedDataBuildSignature skips building the DigestInfo for ML-DSA,
which signs the full message in pure mode and never consumes it.
- wc_PKCS7_MlDsaSign wraps the ML-DSA private-key decode in
PRIVATE_KEY_UNLOCK/PRIVATE_KEY_LOCK. Unlike RSA/ECC, the FIPS module gates
wc_MlDsaKey_PrivateKeyDecode behind the private-key read lock, so signing
would otherwise fail with FIPS_PRIVATE_KEY_LOCKED_E under --enable-fips. The
macros are no-ops in non-FIPS builds.
wolfssl/wolfcrypt/pkcs7.h:
- Document that the fixed-size signer public key buffer (publicKey/publicKeySz)
holds only RSA/ECC keys; it stays RSA-sized.
wolfcrypt/src/hash.c:
- Map the SHAKE128/SHAKE256 OIDs to their hash types in wc_OidGetHash().
certs/mldsa:
- Add expanded-only PKCS#8 DER private keys (mldsa44/65/87-key.der) matching
the self-signed ML-DSA certificates, with README and include.am updates.
The expanded-only shape (no seed) decodes via wc_MlDsaKey_ImportPrivRaw
without keygen-from-seed or the ASN template, so pkcs7signed_mldsa_test also
passes in WOLFSSL_MLDSA_NO_MAKE_KEY and non-WOLFSSL_ASN_TEMPLATE builds.
certs/renewcerts.sh:
- Generate the mldsa<N>-key.der files from the matching mldsa<N>-key.pem in the
expanded-only shape (openssl pkey -provparam ml-dsa.output_formats=priv), so
a regeneration keeps the DER key in step with the cert. The OpenSSL detection
probe now requires both ML-DSA keygen and that conversion across all three
levels, so the block runs fully (matched cert+key) or is skipped entirely
rather than aborting mid-way.
wolfcrypt/test/test.c:
- Add pkcs7signed_mldsa_test(): round-trip encode/verify of SignedData across
ML-DSA-44/65/87, with and without signed attributes, including a check that
the digest algorithm parameters are encoded as expected. The message-digest
OID is selected from the enabled hash set (SHA-512, else SHA-256, else SHA-1)
so the test builds when SHA-512 is disabled. A negative case confirms ML-DSA
rejects a caller-supplied pre-computed content hash with BAD_FUNC_ARG.
test_wc_falcon_sign_verify aborted (SIGABRT) when run as part of the
full unit suite in liboqs configs. The direct OQS_SIG_keypair() call
draws from liboqs' randombytes callback, which wolfSSL points at its
default liboqs RNG; wolfSSL_liboqsClose() (run by wolfCrypt_Cleanup)
frees that RNG without resetting liboqs_init, so after any earlier
Init/Cleanup cycle in the suite the re-Init never re-creates it and
the callback abort()s on the freed RNG. Running the test alone passed,
which is why this only surfaced in make check.
Drop the direct liboqs usage entirely: decode the embedded
bench_falcon_level1_key (certs_test.h) with wc_Falcon_PrivateKeyDecode
and exercise sign/verify through the wolfSSL API only, which hands the
test's own RNG to liboqs and does not depend on the default-RNG
lifecycle. Also removes the oqs/oqs.h include and the OQS_STATUS
handling; with no liboqs symbols left in the body, only the guard
still references HAVE_LIBOQS, easing the planned liboqs removal.
Validated in --with-liboqs --enable-experimental --enable-falcon (the
failing PRB-liboqs config): the full unit suite now completes with the
test passing at the position that aborted; also passes under
opensslall+falcon and compiles clean with -Werror=bad-function-cast.
ExpectIntEQ casts both arguments to int (tests/unit.h ExpectInt), and
casting a function call that returns the liboqs OQS_STATUS enum trips
-Werror=bad-function-cast, which is part of the test warning set. Store
the status in a local first; casting a variable does not trigger the
warning. Broke falcon-enabled configs once the HAVE_PQC guard fix made
this test compile.
Verified: the TU reproduces the exact CI error before this change and
compiles clean after, and test_wc_falcon_sign_verify still passes in a
--disable-md5 --enable-opensslextra --enable-falcon --with-liboqs
build.
Address the PR 10845 review findings:
* test_signature.c: the Falcon sign/verify test was guarded on
HAVE_PQC, which no build system ever defines (--enable-falcon sets
HAVE_FALCON only), so the test always compiled out to skipped. Gate
it on HAVE_FALCON && HAVE_LIBOQS like the library does, and drop the
now-unreferenced HAVE_PQC entry from .wolfssl_known_macro_extras.
Verified with --enable-opensslall --enable-experimental
--enable-falcon --with-liboqs: the test now executes and passes.
* api.c: revert the (OPENSSL_EXTRA || OPENSSL_ALL) widening of the
inner guards of test_wolfSSL_TXT_DB and the new
test_wolfSSL_NCONF_negative_paths. Both functions live inside the
enclosing OPENSSL_ALL block and their TEST_DECLs are OPENSSL_ALL-
gated (and TXT_DB/NCONF themselves are OPENSSL_ALL-only APIs), so
the widening could never take effect. Inner guards now match their
siblings (filesystem/BIO deps only).
* test_pkcs12.c: wrap the expected BAD_FUNC_ARG values of the new
parse guardrail asserts in WC_NO_ERR_TRACE() for consistency with
the rest of the PR's negative-path assertions.
All six affected tests pass in an opensslall+falcon+liboqs build:
falcon_sign_verify, TXT_DB, NCONF, NCONF_negative_paths,
PKCS12_parse_guardrails, PKCS12_create_guardrails.
PRB-generic-config-parser failed in test_wolfSSL_X509V3_EXT under an
OPENSSL_EXTRA (non-OPENSSL_ALL) config:
test_ossl_x509_ext.c:1519 ExpectIntEQ(actual, 0) /* got -5 */
The function walks the OCSP root CA's extensions by hardcoded index (i=0 basic
constraints, i=1 subject key id, i=2 authority key id, ...) and asserts fixed
values. The strcmp result -5 is exactly '2'-'7': the i=1 i2s produced the
authority-key-id value ("27:8E:...") instead of the subject-key-id
("73:B0:..."), i.e. the stored-extension order differs in OPENSSL_EXTRA-only
builds, so the index assumption breaks.
On master this test is gated on OPENSSL_ALL; the MC/DC campaign commit
(bc92090b3) over-widened it to (OPENSSL_EXTRA || OPENSSL_ALL) when splitting
api.c. Revert just this function's guard to OPENSSL_ALL. The by-NID
test_wolfSSL_X509V3_EXT_aia above keeps its OPENSSL_EXTRA widening (that is the
one the AIA leak fix needed, and it looks extensions up by NID so it is
order-independent).
Verified: skipped under --enable-opensslextra (no longer runs/fails there),
runs and passes under --enable-all.
test_wc_RsaDecisionCoverage decrypted an OAEP-SHA256 cipher text as PKCS#1 v1.5
and asserted it must return < 0. That is flaky: v1.5 decrypt-unpadding of the
random OAEP plaintext spuriously "succeeds" whenever byte[1] lands on 0x02 with
a valid 0x00 separator after >=8 nonzero bytes -- a few-percent-per-run coin
flip, and a fresh random key is generated each run. It surfaced as intermittent
make-check failures (e.g. "result: 36 >= 0", "140 >= 0") on PR CI.
Replace it with a deterministic padding-mismatch: decrypt the (no-label) OAEP
cipher text as OAEP with a non-empty label. OAEP authenticates the label via
lHash, so a label mismatch fails the integrity check every time, still
exercising the padding-mismatch decision branch in rsa.c.
Verified locally by looping test_wc_RsaDecisionCoverage 150x in an
OAEP+SHA256 build: old assertion failed 2/150, new assertion 0/150.
PRB-fips-repo-and-harness-test-v3-part1 (FIPS v2, --enable-fips=v2
--enable-opensslextra/--enable-opensslall) failed in test_wc_AesFeatureCoverage.
Reproduced against a real FIPS v2 build (linuxv2 = WCv4-stable module, in-core
integrity hash regenerated)
The PRB-CAVP-selftest-v2 leg (--enable-selftest=v2, frozen wolfCrypt 4.1.0
crypto) failed in test_wc_AesFeatureCoverage.
Reproduced against that exact build; the failing assertion is:
tests/api/test_aes.c:8324
ExpectIntEQ(wc_AesCcmEncrypt(&aes, NULL, NULL, 0, ccmNonce13,
sizeof(ccmNonce13), ccmTag, 16, ccmAad, sizeof(ccmAad)), 0) /* got -173 */
That is the AAD-only (empty-plaintext) CCM case. Current wolfCrypt accepts
NULL in/out when inSz==0; the frozen v4.1.0 wc_AesCcmEncrypt rejects in/out==NULL
unconditionally and returns BAD_FUNC_ARG. Same class as the RsaDecisionCoverage
self-test fix: the frozen module's argument-validation contract predates the
modern behaviour this test asserts.
This function's value is MC/DC of the open wolfcrypt/src/aes.c feature paths,
which is not the aes.c compiled under --enable-selftest, so under self-test it
measures nothing and only risks such divergences. The key-wrap block in this
same function already excludes HAVE_SELFTEST (and the AES *ArgMcdc tests do
too); extend that to the GCM/GMAC and CCM blocks. HAVE_FIPS is intentionally
left running -- that (newer) module honours these paths and never flagged this
test; the open MC/DC campaign builds are unaffected.
Verified: skipped cleanly under --enable-selftest=v2 (test index 278, matching
CI); open build still runs and passes it.
The PRB-CAVP-selftest-v2 leg (./configure --enable-selftest=v2, which overlays
frozen wolfCrypt 4.1.0 crypto) failed in test_wc_RsaDecisionCoverage.
Reproduced against that exact build; the failing assertion is:
tests/api/test_rsa.c:1474
ExpectIntEQ(wc_RsaSetRNG(&key, NULL), BAD_FUNC_ARG) /* got 0 */
So the assertion is correct for current wolfCrypt but not part of the frozen
self-test module's contract. This test's whole purpose is MC/DC of the *open*
wolfcrypt/src/rsa.c decision branches, which is not even the rsa.c compiled
under --enable-selftest, so under self-test it measures nothing and only risks
divergent error codes like this one. The sibling key-gen/decision tests in this
file (test_wc_CheckProbablePrime, the RsaKeyGeneration group) exclude
HAVE_SELFTEST for the same reason; do so here too.
Guard the whole function rather than the single assertion: none of it counts
toward the (open-build) MC/DC campaign under self-test, and a whole-function
guard is robust against any other frozen-vs-current divergence in the same
body. HAVE_FIPS is intentionally left running -- that (newer) module honours
these decisions (and excludes the WC_RSA_BLINDING wc_RsaSetRNG block anyway),
and the open MC/DC campaign builds are unaffected.
Verified: with the guard, the test is cleanly skipped under --enable-selftest=v2
(test index 365, matching CI); the open build still runs and passes it.
A second apple-M1 FIPS segfault (--enable-fips=v5): test_wc_AesCcmArgMcdc probes
the pure-C CCM inSz-overflow decision by calling wc_AesCcmEncrypt/Decrypt with a
1-byte dummy in/out buffer and a claimed length of 65536, relying on the pure-C
path returning AES_CCM_OVERFLOW_E *before* touching the buffer. The FIPS module's
CCM does not reject early, so it writes 65536 bytes into the 1-byte buffer and
segfaults. (The rounds=0 corruption in the same test was already skipped via
WC_TEST_AES_ROUNDS_OFFLOADED, but the two overflow blocks were not.)
Every decision this test targets lives in pure-C aes.c CCM code that is not
compiled in FIPS/self-test builds, so guard the whole function on
!defined(HAVE_FIPS) && !defined(HAVE_SELFTEST) rather than patching each unsafe
block. The other *ArgMcdc tests only corrupt rounds (macro-skipped) and have no
oversized-buffer calls, so they need no further change.
Verified: --enable-all still builds and test_wc_AesCcmArgMcdc passes; the 65536
overflow calls are present non-FIPS and absent when HAVE_FIPS is defined.
The CAVP self-test build (--enable-selftest) failed to compile test_aes.c:
wc_AesGcmSetExtIV (test_wc_AesGcmDecisionCoverage) and wc_Gmac/wc_GmacVerify
(test_wc_AesGmacArgMcdc) are declared only under !WC_NO_RNG in mainline and are
absent from the frozen self-test module's headers (they are present under FIPS -
the apple-M1 FIPS build compiled and passed both), so -Werror=implicit-function-
declaration aborted the build.
Gate those specific calls (and the now-otherwise-unused iv buffer) on
!defined(WC_NO_RNG) && !defined(HAVE_SELFTEST). wc_GmacSetKey stays available, so
its coverage is retained under self-test. FIPS builds are unaffected.
Verified: --enable-all still builds and both tests pass; preprocessing test_aes.c
with -DHAVE_SELFTEST leaves no wc_AesGcmSetExtIV/wc_Gmac/wc_GmacVerify calls in
any always-compiled function (remaining ones are in the WOLFSSL_AESGCM_STREAM
stream test, which the self-test config disables).
test_wc_AesCcmArgMcdc segfaulted on the FIPS builds (apple-M1 config A, CAVP
self-test), exit 139. The AES *ArgMcdc tests reach the post-key-setup "ret != 0"
checkpoints by corrupting aes->rounds = 0 and calling wc_AesCcmEncrypt/Decrypt.
That relies on the pure-C AesEncryptBlocks_C guard (if r==0 return KEYUSAGE_E) to
turn the corruption into a clean error return. Under the FIPS / self-test module
the AES implementation has no such guard, so rounds=0 runs AES with a zero-round
key schedule and dereferences past the key schedule -> SIGSEGV.
The corruption is already gated by WC_TEST_AES_ROUNDS_OFFLOADED (crypto-cb / asm
offload). FIPS and self-test are the same situation - the pure-C guard is not in
the compiled path - so add HAVE_FIPS / HAVE_SELFTEST to that macro. The three
function-level FIPS-guarded tests (SetKey/Modes/Cmac ArgMcdc) were already
skipped; test_wc_AesCcmArgMcdc is not, and its non-corruption CCM coverage now
still runs under FIPS while only the rounds-corruption blocks are skipped.
Verified: --enable-all (non-FIPS) still runs and passes all rounds-corruption
tests; the corruption blocks compile out only under FIPS/self-test.
Adds a wb_aesni() supplement covering the AES-NI-only file-static helpers that
the aesni build variant instruments: AES_set_{en,de}crypt_key_AESNI's
!userKey/!aes guard and the AesGcm{AadUpdate,EncryptUpdate,DecryptUpdate}_aesni
NULL/size guards, using the same "call the static with both halves of the pair"
idiom as the classic GHASH/GHASH_UPDATE supplements.
Closes 6 of the 8 AES-NI null-guard residuals (aesni_wb 14->20, union
384->390/397). The remaining pair is AES_set_decrypt_key_AESNI's !userKey/!aes:
its valid-argument (false) half needs an AES-NI decrypt-key setup that the
current aesni test set does not exercise; left as a documented residual.
This branch widened test_wolfSSL_X509V3_EXT's guard from OPENSSL_ALL to
(OPENSSL_EXTRA || OPENSSL_ALL). The Authority Info Access sub-test frees its
aia stack with wolfSSL_sk_ACCESS_DESCRIPTION_pop_free(aia, NULL), relying on the
stack's type-based element free - but wolfssl_sk_get_free_func() only wires up
wolfSSL_ACCESS_DESCRIPTION_free for STACK_TYPE_ACCESS_DESCRIPTION under
OPENSSL_ALL. In an OPENSSL_EXTRA-only build (now reachable) the NULL callback
frees the stack nodes but leaks each ACCESS_DESCRIPTION (struct + method OBJ +
location GENERAL_NAME + URI string): 370 bytes, caught by ASAN/valgrind.
Pass wolfSSL_ACCESS_DESCRIPTION_free explicitly (available under OPENSSL_EXTRA);
correct under OPENSSL_ALL too. Verified leak-free under ASAN with the failing
config (--enable-opensslextra --enable-crl ... --disable-fastmath).
The branch's Falcon signature test (tests/api/test_signature.c) guards on
HAVE_PQC, which current wolfSSL no longer defines anywhere, so check-source-text
flags it as unknown. Register it alongside the other PQC/MLKEM extras.
clang-tidy (all-c89, async-quic, intelasm) flagged `ccmTag[0] ^= 0x01` as a use
of an uninitialized value: the analyzer does not model wc_AesCcmEncrypt writing
the tag buffer. Zero-initialize ccmTag; the subsequent encrypt still overwrites
it before the tamper, so behavior is unchanged.
Same FIPS-header mismatch as the earlier AesSetKey/Cmac guard: the FIPS v2/v5
modules lack AES_IV_FIXED_SZ and GCM_NONCE_MIN/MID/MAX_SZ and declare
wc_AesEncryptDirect as void, so test_wc_AesModesArgMcdc and test_wc_AesGcmArgMcdc
fail to compile there (fatal under -Werror). Gate both on the modern API with
the same idiom used by the other AES-DIRECT tests.
The apple-m1 "known config A" (FIPS) build broke: the FIPS module's frozen
headers declare wc_AesEncryptDirect/wc_AesDecryptDirect as void (not int) and
omit wc_CmacFree, so the new tests' ExpectIntEQ(wc_AesEncryptDirect(...)) and
wc_CmacFree() usages don't compile.
Gate test_wc_AesSetKeyArgMcdc and test_wc_AesCmacArgMcdc on the modern API with
the same idiom test_wc_AesEncryptDecryptDirect_WithKey already uses:
(!defined(HAVE_FIPS) || !defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION > 6))
&& !defined(HAVE_SELFTEST)
The campaign runs non-FIPS, so no coverage is lost where it is measured.
Verified: --enable-all still builds and both tests run.
The last two red PR jobs, both in the branch's new tests:
- intelasm (ASAN): test_wc_AesKeyExportArgMcdc calls wc_AesInit_Id() and
wc_AesInit_Label() which succeed (allocating the WC_DEBUG_CIPHER_LIFECYCLE
tag) but were never freed -> 8-byte LeakSanitizer leak. Add wc_AesFree()
to both blocks.
- no-client-no-client-auth (minimal server-only build):
test_wolfSSL_session_cache_api_direct's wolfSSL_new() returned NULL because
a certless server CTX has no usable cipher suite. Load the test server
cert/key (file, with a USE_CERT_BUFFERS_2048 fallback) before wolfSSL_new()
in the server-only path; the client path is cert-free as before.
Verified: --enable-all + ASAN run of the aes group is leak-free, and
CPPFLAGS="-DNO_WOLFSSL_CLIENT -DWOLFSSL_NO_CLIENT_AUTH" now passes.
The aes.rounds-validity check that returns KEYUSAGE_E lives only in the
pure-C block encrypt (AesEncryptBlocks_C). On ARMv8 with crypto extensions,
--enable-all auto-enables WOLFSSL_ARMASM, whose asm wc_AesEncrypt bypasses
that check, so corrupting aes.rounds no longer fails the op (returns 0).
This broke the SetKey/CTR/CFB/OFB/CCM/CMAC rounds-corruption assertions on
the arm64 CI runners.
Extend WC_TEST_AES_ROUNDS_OFFLOADED to also cover WOLFSSL_ARMASM (joining
WOLF_CRYPTO_CB_FIND / WOLF_CRYPTO_CB_ONLY_AES). MC/DC of that decision is
still obtained from the pure-C configs in the variant union. x86 (incl.
AES-NI, which does validate rounds) is unaffected.
Three more failures in the branch's added tests, found via the ASAN, C++
and no-client CI configs:
- test_wolfSSL_X509V3_EXT leaked 2296 bytes: the added
X509_get_ext_d2i(x509, NID, &critical, NULL) calls (used to exercise the
critical-flag output) discarded their allocated result. Free each per its
actual return type: BASIC_CONSTRAINTS, ASN1_STRING (key usage),
AUTHORITY_KEYID, AUTHORITY_INFO_ACCESS, and - for subject_key_identifier -
a STACK_OF(ASN1_OBJECT) (wolfSSL_X509_get_ext_d2i wraps a lone obj in a
stack). This was the real cause of the sanitize-asan / intelasm / krb-asan
job failures (the read_write_ex/ECH/dtls13 asserts printed there are
retry-masked and fail identically on master).
- C++ build (all-pq-cxx): void* from X509_get_ext_d2i does not implicitly
convert; add explicit WOLFSSL_X509_EXTENSION* casts.
- no-client link (all-no-client): wolfSSL[_CTX]_UseOCSPStapling[V2] (CSR/CSR2)
are client-side APIs; guard those blocks with !NO_WOLFSSL_CLIENT.
Verified: full --enable-all + ASAN run is leak-free and passes; --enable-all
-DNO_WOLFSSL_CLIENT builds and links.
Three more config-matrix failures in the AES coverage tests:
- Rounds-corruption checks (aes.rounds/cmac.aes.rounds = 0/17 -> expect
KEYUSAGE_E) also break under WOLF_CRYPTO_CB_ONLY_AES, which strips the
software AES so the op is serviced by the callback and ignores the
corrupted struct (same net effect as WOLF_CRYPTO_CB_FIND). Introduce
WC_TEST_AES_ROUNDS_OFFLOADED = (WOLF_CRYPTO_CB_FIND || _ONLY_AES), replace
the previous WOLF_CRYPTO_CB_FIND-only guards with it, and extend it to the
wc_AesEncryptDirect/wc_AesDecryptDirect checks in AesSetKeyArgMcdc (which
the ONLY_AES path also offloads).
- test_wc_AesFeatureCoverage's GCM-streaming block uses a hardcoded 256-bit
key; guard it with WOLFSSL_AES_256 (failed under -DNO_AES_256).
- Its AES-KeyWrap block uses a 192-bit key; guard with WOLFSSL_AES_192
(failed under -DNO_AES_192).
Verified: --enable-swdev --enable-cryptocb ... -DWOLF_CRYPTO_CB_ONLY_AES and
--enable-all -DNO_AES_192 -DNO_AES_256 now both build and pass; a normal
--enable-all build still runs the rounds checks.
Several AES ArgMcdc tests corrupt aes.rounds (or cmac.aes.rounds) and
expect the subsequent op to fail with KEYUSAGE_E from the in-process
software AES path. Under WOLF_CRYPTO_CB_FIND (e.g. --enable-swdev), the
"devId != INVALID_DEVID" guard is removed, so CTR/CCM/CMAC ops are
offloaded to the registered crypto callback even for INVALID_DEVID; the
callback re-derives the key and ignores the corrupted struct, returning 0
instead of KEYUSAGE_E and failing the assertion.
Guard those internal-failure checks with #ifndef WOLF_CRYPTO_CB_FIND
(wc_AesCtrEncrypt, wc_AesCfb/OfbEncrypt/Decrypt, wc_AesCcmEncrypt/Decrypt,
wc_CmacUpdate); the raw-block wc_AesEncryptDirect path in SetKey does not
route through cryptocb, so it stays. (void)-cast the locals only used by
the guarded checks to keep -Werror clean. MC/DC is unioned across configs,
so no union coverage is lost.
Verified: --enable-swdev ... (WOLF_CRYPTO_CB_FIND) now passes, and a
non-CB_FIND build with all these modes still runs and passes the checks.
The check-source-text CI job flags non-ASCII (8-bit) bytes in source. The
new MC/DC tests and README used UTF-8 punctuation in comments/prose
(em-dash, ellipsis, left-right arrow). Replace with ASCII equivalents
(-, ..., <->). Verified: ./.github/scripts/check-source-text.sh on the
changed files reports clean.
The new MC/DC coverage tests broke many CI configs under -Werror (which is
auto-enabled for in-git-tree builds). Fixes, each verified with a real
-Werror build of the relevant config:
- test_aes.c: wrap the whole test_wc_AesSivArgMcdc definition in
WOLFSSL_AES_SIV && WOLFSSL_AES_128 (was body-only guarded while its
prototype is guarded) -> fixes -Wmissing-prototypes when SIV is off.
- test_aes.c: mark key/in/out (void) in test_wc_AesModesArgMcdc; they are
used only by the per-mode (CTR/CFB/OFB) blocks -> fixes -Wunused-variable
when no such mode is enabled.
- api.c: guard the test_CryptoCb_* callback helpers with
WOLF_CRYPTO_CB && WOLFSSL_TEST_STATIC_BUILD to match their only caller
-> fixes -Wunused-function in cryptocb non-static builds.
- api.c: register test_wc_CryptoCb_registry under its actual definition
condition (WOLF_CRYPTO_CB && HAVE_IO_TESTS_DEPENDENCIES && !ONLY_*) and
keep test_wc_CryptoCb registered unconditionally (as on master)
-> fixes undeclared / defined-but-unused across cryptocb configs.
- api.c: declare session-cache 'mode' under OPENSSL_EXTRA (its only uses)
-> fixes -Wunused-variable without opensslextra.
- api.c: guard the Enable/DisableOCSPStapling calls in
test_wolfSSL_crl_ocsp_object_api with HAVE_CERTIFICATE_STATUS_REQUEST[_V2]
-> fixes undefined references with OCSP but no stapling.
Verified clean under: --enable-ocsp --enable-ocspstapling, --enable-ocsp
(no stapling), and --enable-all; unit.test runs pass.
test_wc_AesModesArgMcdc asserted that wc_AesCtrEncrypt() with corrupted
aes.rounds returns KEYUSAGE_E, but used sz = 32 (an exact block multiple).
When in != out, the full blocks are consumed by a batch path that does not
surface the per-block rounds error - the AES-NI batch, or the HAVE_AES_ECB
fast path which ignores wc_AesEcbEncrypt()'s return - leaving no trailing
partial block, so the function returns 0 and the assertion fails. This was
latent (the whole test binary failed to link before the visibility fix) and
reproduces in --disable-aesni --enable-aesecb builds.
Use a non-block-multiple size (WC_AES_BLOCK_SIZE + 4) so the
"(ret == 0) && sz" leftover-handling call runs and fails on the corrupted
rounds via wc_AesEncrypt() in every backend. Reported by Copilot review on
PR #10845.
Verified: test_wc_AesModesArgMcdc now passes under --disable-aesni
--enable-aesecb (previously failed) and under --enable-aesni --enable-aesecb.
Several MC/DC coverage tests called WOLFSSL_LOCAL (hidden-visibility)
library functions directly from the in-tree unit.test:
- wc_AesCcmCheckTagSize() (test_aes.c)
- wc_CryptoCb_Init/Cleanup/GetDevIdAtIndex() (api.c)
These only link when the library is built with test-static visibility, so
normal (shared) builds failed at link with "undefined reference", breaking
essentially every CI build job. Gate the affected assertions on
WOLFSSL_TEST_STATIC_BUILD (in addition to the existing feature guards) so
they compile out where the symbols are hidden, matching the existing
wolfSSL convention for internal-symbol tests.
Verified: ./configure --enable-all (no WOLFSSL_TEST_STATIC_BUILD) now
builds tests/unit.test cleanly and the full suite passes.
Add tests/unit-mcdc/, a standalone white-box program that compiles
wolfcrypt/src/aes.c directly to reach static/WOLFSSL_LOCAL helpers
(GHASH/GHASH_UPDATE ptr guards, _AesNew_common cross-arg checks) that
are structurally unreachable through the public API, closing 19 of the
AES MC/DC residuals. Extend tests/api/test_aes.{c,h} with the
decision/feature coverage cases these build on.
These are for the external ISO 26262 per-module MC/DC campaign; they do
not change library behaviour and are not part of the wolfSSL build.
For each product (wolfSSH, wolfCLU, wolfTPM, wolfMQTT, wolfPKCS11, wolfProvider) this builds wolfSSL and then builds the product against it, at both the product's latest release tag and its master branch. It only checks that they compile, it does not run any tests. If a wolfSSL change breaks a product's latest release on purpose, you say so in a commit message with breaks-<product>=<tag>. A break on a product's master is not allowed and has to be fixed.
breaks-wolfssh=v1.5.0-stable
Note: wolfSSH v1.5.0-stable does not currently compile against wolfSSL. This commit did not break it, it adds the cross-library check that discovered the break. The token above declares it so the new check tracks it as a known break instead of failing red, until wolfSSH ships a fixed release.