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.
The generic wc_AesEncrypt/wc_AesDecrypt (aes.c) reject an AES object
whose key schedule was never set (rounds outside 1..7 after halving)
with KEYUSAGE_E, and every mode inherits that through their int return.
The RISC-V port's block helpers are void, so nothing reported unkeyed
use: wc_AesEncryptDirect and wc_AesCcmEncrypt/Decrypt silently
processed with a garbage schedule, and wc_AesCtrEncrypt classified it
as BAD_FUNC_ARG instead of KEYUSAGE_E.
Align the port with the generic error contract:
* wc_AesEncryptDirect / wc_AesDecryptDirect: add the generic rounds
check (also fixes wc_CmacUpdate error reporting, which goes through
wc_AesEncryptDirect on this port)
* wc_AesCcmEncrypt / wc_AesCcmDecrypt: same check after the argument
sanity block
* wc_AesCtrEncrypt (both variants): the existing rounds switch now
returns KEYUSAGE_E instead of BAD_FUNC_ARG
Found by the ISO 26262 MC/DC campaign argument-matrix tests
(test_wc_AesSetKeyArgMcdc, test_wc_AesModesArgMcdc, test_wc_AesCcmArgMcdc,
test_wc_CmacArgMcdc) under qemu-riscv64.
Align the RISC-V AES port's argument validation with the generic aes.c
implementations (and with the port's own vector/scalar-crypto siblings):
* wc_AesSetKey (base assembly variant, i.e. neither
WOLFSSL_RISCV_VECTOR_CRYPTO_ASM nor WOLFSSL_RISCV_SCALAR_CRYPTO_ASM):
reject key == NULL. The vector and scalar-crypto variants of the same
function already check it; the base variant passed NULL through to the
key expansion and wc_AesGcmSetKey then dereferenced the uninitialized
schedule, crashing on e.g. wc_AesGcmSetKey(aes, NULL, 16).
* wc_AesCcmEncrypt / wc_AesCcmDecrypt: reject authIn == NULL when
authInSz > 0, as the generic implementation does. The port otherwise
walks the NULL authIn buffer while computing the CBC-MAC.
Found by the ISO 26262 per-module MC/DC campaign's argument-matrix tests
(test_wc_AesGcmSetKey, test_wc_AesCcmArgMcdc) running the RISC-V port
under qemu-riscv64: upstream CI only exercises this port with the KAT
suite, which never passes invalid arguments.
Server-side PKCS#7 encode improvements that let downstream EST/SCEP enrollment
code (wolfCert) drive the existing encoder through the public API rather than
hand-rolling DER. Everything is gated under the existing HAVE_PKCS7 — no new
build options and no new public functions; the convenience wrappers live
caller-side.
Allow degenerate (certs-only) SignedData encode
Relax the hashOID != 0 requirement in PKCS7_EncodeSigned() when
sidType == DEGENERATE_SID, so a caller can produce a certs-only bundle (no
signer, attributes, or eContent — the form used by EST /cacerts and SCEP
GetCACert) by selecting DEGENERATE_SID via wc_PKCS7_SetSignerIdentifierType()
and calling wc_PKCS7_EncodeSignedData(). The output round-trips through
wc_PKCS7_VerifySignedData().
Size the signed-attribute array to the actual count
The SignerInfo attribute working array is now sized to the real attribute
count instead of a fixed [7] array. An inline buffer (sized
MAX_SIGNED_ATTRIBS_SZ, the historical footprint) covers the common
allocation-free case; a heap buffer is used only when the count exceeds it.
The default-attribute count comes from a single helper
(wc_PKCS7_GetDefaultSignedAttribCount) so the sizing matches the emission
logic exactly, and the canned-attribute write is bound-checked against the
array capacity. This also fixes a latent overflow where the backing array was
hardcoded [7] while the bound check used MAX_SIGNED_ATTRIBS_SZ. The macro is
retained for source compatibility but no longer caps the count.
Document the decoded-attribute value shape
Documented the stable shape of PKCS7DecodedAttrib.value (the contents of the
SET OF AttributeValue, outer SET tag stripped) so callers can rely on it. No
behavior change.
Fix multi-certificate decode in non-streaming builds
Bound the additional-certificate loop in wc_PKCS7_VerifySignedData against the
absolute end of the certificate set (idx + length) rather than the relative
length. In NO_PKCS7_STREAM builds the old bound dropped trailing certificates
(all but the first when a large eContent preceded the set), failing
verification when the signer cert was among those dropped. Streaming builds
were unaffected.
Tests
Added coverage in pkcs7signed_test: degenerate certs-only encode via the
public API, nine-attribute encode (beyond the inline capacity), decoded
attribute value shape for PrintableString and OCTET STRING, and a
multi-certificate decode regression with large content that triggers the
bound bug under NO_PKCS7_STREAM. Added a signed-attribute selection
round-trip covering a messageDigest-only subset and the no-attributes case
via wc_PKCS7_SetDefaultSignedAttribs/wc_PKCS7_NoDefaultSignedAttribs, a
WOLFSSL_NO_MALLOC over-capacity case that must return BUFFER_E instead of
overrunning the inline buffer, and a malformed certificate-set length that
exercises the certSetEnd clamp in the verifier. Config-sensitive cases are
guarded.