Adds an opt-in callback that takes over the peer certificate trust
decision. wolfSSL builds no chain, verifies no signature and checks no
date, revocation status, key usage or host name; the verify callback is
not called either. The callback gets only the DER certificates from the
Certificate message as WOLFSSL_BUFFER_INFO entries, certs[0] first. It
is consulted even under WOLFSSL_VERIFY_NONE, and its rejection fails the
handshake either way.
wolfSSL still decodes every certificate with ParseCert(NO_VERIFY) before
the callback runs, so malformed DER fails the handshake and the callback
is never handed it. Content wolfSSL does not understand - an unknown
critical extension, an unsupported key or signature algorithm, a
signature algorithm mismatch - is not a decoding failure and is left for
the callback to judge. The check runs once, not again on re-entry after
a deferred verdict.
The callback may return CHAIN_VERIFY_WANT_E to suspend the handshake and
be asked again with the same certificates when the application re-enters
wolfSSL_connect(), wolfSSL_accept(), wolfSSL_read() or wolfSSL_write().
A certificate received after the handshake (TLS 1.3 post-handshake
authentication) arrives inside wolfSSL_read() and is resumed by reading
again: ReceiveData() re-enters on any handshake-suspend error, and the
ticket-sent accept state leaves a suspended message alone. Rejection
fails with CHAIN_VERIFY_CB_E and one bad_certificate alert, and sets
peerVerifyRet so wolfSSL_get_verify_result() does not report X509_V_OK.
Still applied: an empty Certificate message keeps the existing
mutual-auth policy (the callback is not called for it), and the minimum
peer key sizes still gate the peer's own key, which the handshake uses
directly.
DTLS, raw public keys and OCSP stapling are not supported with the
callback. wolfSSL_CTX_SetChainVerifyCb() and wolfSSL_SetChainVerifyCb()
refuse with CHAIN_VERIFY_UNSUPPORTED_E when the context or object is
already configured for one of them, and a connection that uses one of
them anyway fails with the same error and an internal_error alert before
the callback is called. The DTLS paths are otherwise untouched.
The callback and its user context can be set on the context or on the
SSL object, the object's taking precedence. The feature is part of
--enable-all, has a CMake option and Doxygen entries.
The suspend machinery is shared with WOLFSSL_NONBLOCK_OCSP and
WOLFSSL_ASYNC_CRYPT. The open-coded pairs of comparisons against
WC_PENDING_E and OCSP_WANT_READ are replaced by IsHsSuspendErr(), and the
matching build guards by WOLFSSL_HAVE_HS_SUSPEND. That also closes three
holes which affected WOLFSSL_NONBLOCK_OCSP builds:
- DoHandShakeMsg() freed ssl->pendingMsg on a non-WC_PENDING_E suspend
while ProcPeerCertArgs still pointed into it.
- wolfSSL_connect()/wolfSSL_accept() and their TLS 1.3 counterparts
called FreeAsyncCtx() when buffered output flushed, discarding the
saved certificate state.
- ProcessPeerCerts() XFREE'd args in WOLFSSL_SMALL_STACK builds without
WOLFSSL_ASYNC_CRYPT, where args points inside ssl->async.
Add an enterprise option that includes all items that would be required.
Update CMake build to match autotools. Added enterprise option.
Added CI loops for configuration options.
Add document that maps the OpenSSL configuration options to wolfSSL's.
Checked against various versions of OpenSSL.
Without NO_SESSION_CACHE_REF, wolfSSL_get_session() returns a reference into
the process-global client cache rather than a session object. That reference
is valid only while the slot it names still holds the session it was issued
for, which the caller cannot observe, so the safe use of the API is the one
the macro selects. Only the integration recipes defined it, and none of them
for that reason: --enable-opensslextra and --enable-opensslall, which is what
an application written against SSL_get_session() reaches for, left it unset.
settings.h now defines NO_SESSION_CACHE_REF unless WOLFSSL_SESSION_CACHE_REF
is defined, so every build selects it, including the user_settings.h, IDE and
bare-metal builds that have no configure step. Putting the rule in the header
rather than only in configure and CMake means no project has to add a macro to
keep the safe behaviour, and the ones that want the deprecated reference ask
for it instead. --enable-session-cache-ref and -DWOLFSSL_SESSION_CACHE_REF=yes
define that opt-in macro, and options.h records it alongside the negative one
so an application cannot disagree with the library it links.
A build that opts in warns at compile time and the warning names
WOLFSSL_SESSION_CACHE_REF_WARNED, which silences it while keeping the path. It
sits inside the NO_SESSION_CACHE region, so a build without a session cache
and a wolfCrypt-only build stay quiet, and it takes the #warning / #pragma
message form already used for WOLFSSL_KEYLOG_EXPORT_WARNED.
The recipes that define NO_SESSION_CACHE_REF on their own keep doing so and
still win over the option. Both build systems say so rather than leaving a
reported option disagreeing with the build: configure warns and clears its
summary line, CMake warns and syncs the cached option. configure also treats
TITAN_SESSION_CACHE as a conflict, because settings.h derives the macro from
it and that never reaches the compile line for a flag scan to find.
The os-check session-cache-ref entry existed because --enable-opensslextra
left the macro unset. It now asks for the reference path explicitly, or
test_wolfSSL_client_cache_id_overwrite would skip and the generation check
added with it would be covered nowhere.
Anything migrating has one lifetime difference to mind: the deprecated
reference stayed valid after wolfSSL_free(), the session object does not, so
code holding the result of wolfSSL_get_session() past the WOLFSSL it came from
has to move to wolfSSL_get1_session() and wolfSSL_SESSION_free().
write_basic_package_version_file() was given only MAJOR.MINOR, so a
CMake-installed 5.9.4 reported itself as 5.9. find_package(wolfssl
5.9.4 CONFIG) then rejected the very release it asked for, and no
consumer could require a patch release. The autoconf-generated version
file and the CMake-generated wolfssl.pc already carry the full version.
The consumer test now asserts a MAJOR.MINOR.PATCH package version, and
the interworking workflow runs it against a CMake install as well as
the autoconf one; only the autoconf install was consumed before.
wolfcrypt/test/test.c: work around false positive cppcheck nullPointer warning in random_bank_test().
CMakeLists.txt, cmake/options.h.in: add WOLFSSL_SLHDSAVERIFYONLY.
wolfcrypt/src/random.c: allow WC_HAVE_RNG_BANKREF with HAVE_FIPS if WOLFSSL_FIPS_DEV.
wolfssl/wolfcrypt/random.h:
* remove WC_RNG_BANK_SUPPORT from the exclusion list for WC_RNG_LOCK_ATFORK
* pivot WC_HAVE_RNG_BANKREF on WC_RNG_WANT_BANKREF_SUPPORT, with FIPS exclusion.
wolfcrypt/src/rng_bank.c: update wc_InitRng_BankRef_local() and wc_BankRef_Release() to use WC_RNG_FLAG_BANKREF, not WC_DRBG_BANKREF.
wolfssl/wolfcrypt/rng_bank.h: remove backward-compat clause defining WC_HAVE_RNG_BANKREF.
linuxkm/lkcapi_rsa_glue.c: refactor km_rsa_ctx_init_rng() to check ctx->rng.flags, not ctx->rng.status, for bankref status.
configure.ac: in ENABLED_RNG_BANK setup, split out WC_RNG_WANT_BANKREF_SUPPORT as a separate flag, and don't define it if FIPS.
wolfcrypt/benchmark/fips_cast_bench.c: omit bench_pct_slhdsa() if defined(WOLFSSL_SLHDSA_VERIFY_ONLY).
wolfcrypt/test/test.c: in myCryptoDevCb(), add HAVE_INTEL_RDRAND to list of macros enabling use of wc_RNG_GenerateBlock() for WC_ALGO_TYPE_RNG.
linuxkm/Makefile: use bash-4.3-compatible syntax in $(()) expression.
.wolfssl_known_macro_extras: remove unneeded entries.
Every build hashed each handshake message with SHA-512 and reserved two Hashes
structures for the TLS 1.2 Finished and CertificateVerify digests, whether or
not TLS 1.2 was compiled in. TLS 1.3 hashes the transcript with the cipher
suite's hash, and WOLFSSL_TLS13_SHA512 is what allows SHA-512 to be that hash,
though no cipher suite in the table selects it today. TLS 1.3 also derives
Finished and CertificateVerify differently, so a TLS 1.3 only build never reads
any of it.
Keep verifyHashes and certHashes only when TLS 1.2 is enabled, and the SHA-512
transcript only when TLS 1.2 or WOLFSSL_TLS13_SHA512 is. A TLS 1.3 only build
drops the handshake hashes from 864 to 352 bytes per handshake and stops
running SHA-512 over every handshake message. Note that ./configure
--disable-tlsv12 does not by itself define WOLFSSL_NO_TLS12, so an autotools
build gets the saving only when that macro is set.
Add --enable-tls13-sha512 and the matching CMake WOLFSSL_TLS13_SHA512 option,
so a macro that now decides the layout of the handshake hashes is recorded in
the generated wolfssl/options.h like every other one.
Guard the --disable-tlsv12 consistency checks on TLS being enabled, the
way configure.ac already does: a wolfCrypt-only build has no handshake to
be left without, so demanding TLS 1.3 of it is wrong. Before this,
cmake -DWOLFSSL_TLS=no -DWOLFSSL_TLSV12=no -DWOLFSSL_TLS13=no failed to
configure.
WOLFSSL_TLS was declared 1450 lines below the checks, so testing it in
place would have read an empty cache variable and silently disabled all
four checks; move its declaration up beside the other TLS version
options instead.
Carry over the other half of the configure.ac rule while here: a TLS
1.3-only build without session tickets has no session to cache, so it
needs NO_SESSION_CACHE. That define had no options.h.in entry, which
would have left the library compiled with it and every application
without it.
A hardware key store holds keys with a lifetime of their own, and none of the
existing callbacks can manage them. WC_ALGO_TYPE_SETKEY and
WC_ALGO_TYPE_EXPORT_KEY are bound to a wolfCrypt key object and carry material
for that object's own use: neither can name a stored key, ask for one to be
created exportable, or make one outlive the object that used it. Wrapped keys
add a second reason, since a wrapped blob never becomes plaintext on this side
of the boundary at all.
Add a dedicated algorithm type covering the operations that manage a stored
key, whether or not they cross that boundary:
WC_KEYSTORE_IMPORT_PLAIN place plaintext key material into a slot
WC_KEYSTORE_EXPORT_PLAIN read a stored key back as plaintext
WC_KEYSTORE_IMPORT_WRAPPED unwrap a blob directly into a slot
WC_KEYSTORE_EXPORT_WRAPPED wrap a stored key back out
WC_KEYSTORE_DERIVE derive slot to slot without touching RAM
WC_KEYSTORE_DELETE destroy a stored key
WC_KEYSTORE_GET_INFO query what a slot holds
The plaintext pair is what most key stores outside the secure-element class
offer, and it is the shape wc_Pkcs11StoreKey() already implements privately:
that function takes a Pkcs11Token* rather than a devId, so an application using
it is bound to PKCS#11 even though the operation is generic. Devices that hold
keys which may never appear in plaintext decline the pair and offer only the
wrapped form.
Delete is deliberately separate from WC_ALGO_TYPE_FREE: freeing a wolfCrypt key
object must never destroy the hardware key it refers to.
A key reference is not a new naming scheme. It is the identifier
WOLF_PRIVATE_KEY_ID already uses, so the bytes that name a key here are the
bytes wc_ecc_init_id() or wc_AesInit_Id() take to bind an object to that key,
and the bytes read back from key->id afterwards. wolfCrypt copies them through
without inspection.
Two details come from building the NXP EdgeLock port against this surface,
which is what a design like this needs before it is fixed in place.
Every operation that creates a key takes keyType, because a key store has to
know what a key is for before it can set its permissions, and the material
does not always say. Raw bytes carry no metadata, and neither does a bare
RFC 3394 wrap, which is a pure data transformation. A vendor container that
carries its own property word stays authoritative over what it holds and
keyType is then a cross-check, which catches the right blob going into the
wrong kind of slot; a device must refuse a mismatch rather than silently
prefer one source. WC_KEYSTORE_KEY_NONE leaves the choice to the device. The
export operations take no keyType, since the key already exists and GET_INFO
reports it.
attrs travels with every creating operation for the same reason, but as a
source only. A format carrying no attributes of its own leaves attrs as the
device's only word on what the new key may do. A container that carries them
wins and attrs is ignored, and it cannot usefully be cross-checked there:
a container's attributes are inside the wrap and are not known until the key
exists, whereas keyType is checkable up front against the reference being
imported into. wc_KeyStore_GetInfo() is how a caller confirms what an import
produced.
keyType also fixes how plaintext material is encoded, so no further argument
is needed to say. A symmetric type takes the raw key bytes; an asymmetric type
takes DER, a private key as PKCS#8 PrivateKeyInfo and a public key as
SubjectPublicKeyInfo. Stating it matters: WC_KEYSTORE_KEY_ECC_SIGN and a byte
string do not otherwise say whether the bytes are a scalar, SEC1 or PKCS#8,
and two devices could each pick differently and both be defensible.
Keys that act on other keys need naming. Without WC_KEYSTORE_KEY_WRAP and
WC_KEYSTORE_KEY_DERIVE a device asked about a wrapping key can only answer
NONE, which is indistinguishable from an empty slot and defeats the point of
GET_INFO. Measured on hardware, a 256-bit wrapping key reported type 0 with
256 bits, which tells a caller nothing about what it may do with it. Both are
listed ahead of the algorithm types, since they name what a key acts on rather
than which algorithm it serves.
The algorithm types cover what the two other backends this was checked against
actually store. wc_Pkcs11StoreKey() handles RSA, ECC and ML-KEM today, and
wolfHSM's WH_KEY_ALGO_ENUM names RSA, ECC, Curve25519, Ed25519, ML-DSA, ML-KEM,
LMS and XMSS, so a shorter vocabulary would have left the facility unusable to
both for anything but symmetric keys.
An algorithm serving two purposes a key store grants separately is split, since
one key doing both is the key-separation problem and a caller has to be able to
ask for the narrower key. RSA and ECC are the only two: PKCS#11 carries
CKA_SIGN and CKA_DECRYPT independently for RSA, and CKA_SIGN against CKA_DERIVE
for ECC. wolfCrypt's own PKCS#11 layer honours that for ECC, selecting from the
ecc_key flags, but sets both CKA_DECRYPT and CKA_SIGN unconditionally for RSA
because no equivalent RsaKey flag exists; expressing the distinction here is
what would let that be tightened later. The remaining types serve one purpose
each and are not split. Signature use is listed before agreement or transport
use throughout.
Argument order follows one rule: two interchangeable control words are never
left adjacent, because a transposition between them compiles cleanly and
surfaces much later as an unrelated-looking failure. An earlier arrangement had
attrs and kdfType separated only by a pointer and a length, and swapping them
silently created a key without the exportable attribute, whose export then
failed two operations away from the mistake. Beyond that each control word sits
beside what it describes. wc_KeyStore_ImportPlain is the one place the two aims
collide and the first wins: attrs sits at the tail of every creating operation
rather than beside keyType, because WC_KEYSTORE_ATTR_EXPORTABLE and
WC_KEYSTORE_KEY_WRAP are both 1 and a swap would be silent. All three creating
operations therefore read keyRef, keyRefSz, keyType, then what they draw the
key from, then attrs.
kdfType refers to enum wc_KdfType, and WC_KDF_TYPE_NONE asks for the device's
own derivation, which is all many key stores offer.
Attributes are fixed when a key is created; hardware generally burns them in,
so there is no operation here to change them afterwards. They round-trip: a
device that can represent one must report it back through GET_INFO, so a caller
can ask whether an export is permitted rather than attempting one and
interpreting the error. Attributes the device cannot represent read as absent,
and out parameters it does not fill are cleared rather than left holding the
caller's stack.
Gated behind WOLF_CRYPTO_CB_KEYSTORE, with tests in wolfcrypt/test and
tests/api that assert each operation reaches the device carrying the arguments
the caller passed, not merely that the call returned zero.
Fix guard around inclunde of chacha20_poly1305.h in internal.h for when
session ticket is not ChaCha20-Poly1305.
Fix port allocation and readiness testing in scripts.
Fix other issues in the scripts as well.
Update test.h code around ready file.
For LTO compiles, all functions must be used.
Make sure the assembly functions are marked as 'used' when not called
internally.
Fix a race in the example client that intermittently failed
scripts/unit.test on TLS 1.3 non-blocking session resumption.
RISC-V 64-bit: s0 needed but functions need to omit frame pointer.
Have source matching generated code again.
Excluded and permitted directoryName subtrees were compared with a byte
prefix memcmp, so a leaf DN escaped an exclusion by varying case, string
type or spacing.
Compare the RDN sequence per RFC 5280 Sec. 7.1 instead.
UTF-8 decoding provided by wc_Utf8_DecodeChar() in coding.c.
Address Skoll review findings on the SealSQ VaultIC port:
- CMake: compile vaultic.c (BUILD_VAULTIC flag + LIB_SOURCES) and stop
excluding vaultic.h from install when the option is on (HIGH-1).
- Crypto callback EC keygen: resolve the curve via key->dp instead of the
ECC_CURVE_DEF that wc_ecc_make_key() forwards, so P-256 keygen offloads to
the device instead of silently falling back to software (HIGH-2).
- EccSharedSecretCb: test the 1.3 versions explicitly instead of a "< 1.3"
ordering compare, which was false for DTLS and skipped client keygen (HIGH-3).
- LoadCertificates: reject cert sizes <= 0 and bound them with
VAULTIC_MAX_CERT_SZ before XMALLOC (HIGH-4); load the device cert before the
CA into the trust store; use WOLFSSL_FATAL_ERROR (not WC_HW_E) for cert
parse/load failures (LOW-14/16).
- Guard the caller's output buffer size (BUFFER_E) before writing the ECDH
shared secret in both the PK and crypto callbacks (MEDIUM-6).
- vaultic.h: guard the ECDH declarations with VLT_TLS_NO_ECDH to match
vaultic.c and rename otherKey to otherPubKey (MEDIUM-7).
- configure.ac: parse --enable-vaultic before the crypto-callback aggregation
so CRYPTOCB/PKCALLBACKS are promoted ahead of the dependent checks (MEDIUM-9).
- Add NULL/dp guards to the PK callbacks (LOW-15).
- Register WOLFSSL_VAULTIC_DEBUG in .wolfssl_known_macro_extras and document
it, the single-device-key routing, and the one-handshake concurrency limit
in the README (LOW-10, MEDIUM-5, MEDIUM-8).
Merge the nine wc_falcon_*.c cores into wolfcrypt/src/falcon.c, matching the
one-file-per-algorithm convention (ed25519.c, wc_mldsa.c). Sign and keygen are
gated internally on WOLFSSL_FALCON_VERIFY_ONLY and the internal helpers become
static. The fpr/fft/poly primitives stay external (shared with the separate
AVX2/NEON FFT backends) so their three headers are retained; the other five
internal headers are removed.
- cmake/functions.cmake: remove duplicated BUILD_FALCON conditional block;
BUILD_FALCON is now set in one place.
- wolfssl/wolfcrypt/include.am: list the internal wc_falcon_*.h headers under
an "if BUILD_FALCON" block so they ship in "make dist" tarballs and install
when Falcon is enabled (the public falcon.h was already listed). Automake
distributes both branches of the conditional, so a Falcon-disabled dist
still contains them.
- wc_falcon_fft_neon.c: fix strict-aliasing UB in falcon_FFT/falcon_iFFT.
fpr is a word64 bit pattern; casting fpr* to double* and using
vld1q_f64/vst1q_f64 accesses the store through the wrong type and can
miscompile at -O2/-O3. Load/store through uint64_t (the real object type)
and reinterpret the vector register to/from f64 via new FALCON_VLD/FALCON_VST
macros. Verified under qemu (NEON_FFT_PASS) with fmla v.2d still emitted.
- wc_falcon_sampler.c / wc_falcon_sampler.h: falcon_prng_get_u8/get_u64 have
no error return, so a SHAKE256 squeeze failure previously went unnoticed and
stale buffer bytes could feed the signer. Add a sticky "err" field latched on
the first refill failure.
- wc_falcon_sign.c: falcon_sign_core now rejects the signature when the PRNG
latched an error, and falcon_do_sign_tree bounds its restart loop
(FALCON_SIGN_MAX_RESTARTS) so a wedged sampler terminates instead of
spinning forever. The bound is far beyond any legitimate restart count.
Falcon was the last algorithm backed by liboqs; now that wolfCrypt has a
native Falcon implementation, liboqs is no longer needed. Remove the
integration entirely so liboqs does not appear as a build or SBOM dependency:
- configure: drop --with-liboqs (and the -loqs link), the BUILD_LIBOQS
conditional and the summary line.
- CMake: drop WOLFSSL_OQS, the duplicate liboqs-backed WOLFSSL_FALCON
option, the OQS cross-validation / find_package(OQS) block, the
FindOQS.cmake module, BUILD_OQS_HELPER, and HAVE_LIBOQS from options.h.in.
- Remove the wolfcrypt/src/port/liboqs port layer (liboqs.c/.h) and its
wolfSSL_liboqsInit/Close calls in wc_port.c.
- settings.h: drop HAVE_LIBOQS from the asym key import/export aggregates
(HAVE_FALCON already covers them) and from the experimental gate; add
HAVE_FALCON to the experimental gate so the unstandardized Falcon requires
WOLFSSL_EXPERIMENTAL_SETTINGS in every build system.
- Drop liboqs.c from the VS/Zephyr/INTIME project files, remove the liboqs
install from Docker, and update INSTALL/tls.c text (Falcon is native now).
No functional change to non-Falcon builds; the library links no liboqs.
Add a complete native Falcon post-quantum lattice signature implementation to
wolfCrypt, replacing the liboqs wrapper. Full key generation, signing and
verification for Falcon-512 (level 1) and Falcon-1024 (level 5).
- Public API wc_falcon_* / falcon_key in falcon.c wraps the native core
(falcon_native_* in wc_falcon.c) plus wc_falcon_{fpr,fft,poly,sampler,
codec,keygen,sign,bigint}.c. No liboqs dependency.
- Portable, constant-time integer-emulated floating-point (fpr) backend is
the default; opt-in per-architecture acceleration:
--enable-falcon-double inline native double
--enable-falcon-asm x86-64 SSE2 out-of-line fpr asm
--enable-falcon-avx2 x86-64 AVX2 (4-wide) FFT
- Division-free (Barrett) integer NTT on the verify path, so no hardware
divide is required on Cortex-M / embedded targets.
- Verify uses a cached twiddle-factor NTT; signing uses the FFT / ffLDL tree
and discrete Gaussian sampler over the abstract fpr seam.
- test.c falcon_test (KAT verify + native keygen/sign/verify roundtrip);
scripts/falcon-interop.c and a CI workflow cross-check native<->liboqs in
both directions.
CMake wired only the LMS sha256-192 and no-sha256-256 variants, while
autotools --enable-lms also supports verify-only, small and shake256. Add
the three missing sub-options (WOLFSSL_LMSVERIFYONLY, WOLFSSL_LMSSMALL,
WOLFSSL_LMSSHAKE256), emitting WOLFSSL_LMS_VERIFY_ONLY, WOLFSSL_WC_LMS_SMALL
and WOLFSSL_LMS_SHAKE256, and expose them in the generated options.h so the
CMake and autotools LMS configurations match.