Commit Graph

623 Commits (be9f43a0ea2d7dbc2cb2258b6da0ddfa3d50b069)

Author SHA1 Message Date
lealem47 4408ad81ca
Merge pull request #11430 from kaleb-himes/wolfEntropy-gets-a-version
Add a version API for wolfEntropy and update dox
2026-09-14 08:55:13 -06:00
JacobBarthelmeh d53764cc88
Merge pull request #11320 from rizlik/dtls13-cid-tx-output-size
Dtls13: cid tx output size
2026-09-11 14:30:41 -06:00
JacobBarthelmeh 92649a1deb
Merge pull request #11425 from Frauschi/keystore_api_fix
cryptocb: let wc_KeyStore_Derive() request the key size
2026-09-11 10:18:37 -06:00
JacobBarthelmeh 1e46e2fc65
Merge pull request #11424 from Frauschi/ed448-make-public-store-pub
Ed448 pub key fix
2026-09-11 09:55:26 -06:00
Tobias Frauenschläger a2cd261da3 Key ID initializer fail on a positive-length null ID
Fixes F-11154 , F-11160 , F-11159 , F-11158 , F-11157 , F-11156 , F-11155.
2026-09-11 17:44:32 +02:00
Tobias Frauenschläger c13851567d Reject XMSS public-key export before a key exists
wc_XmssKey_ExportPub_ex and wc_XmssKey_ExportPubRaw checked only for NULL
arguments. Parameters are populated by wc_XmssKey_SetParamStr, well before
wc_XmssKey_MakeKey, wc_XmssKey_Reload or an import produces a public key, so
a caller that had merely selected a parameter set received a zeroed public
key and a success return. The export path also marked the destination
verify-only, and wc_XmssKey_PublicKeyToDer encoded the result as a valid
RFC 9802 SubjectPublicKeyInfo.

Require the OK, VERIFYONLY or NOSIGS state in both exporters, and check it
before the destination key is zeroized so a rejected call leaves it
untouched. wc_XmssKey_GetPubLen keeps its parameter-only contract, since
sizing a buffer ahead of key generation is what callers use it for. Cover
the parameter-only case in the XMSS decision coverage test and in the
white-box export guards.

Fixes F-8151.
2026-09-11 17:44:32 +02:00
Tobias Frauenschläger 54e3c09446 Reject LMS raw public-key export before a key exists
wc_LmsKey_ExportPubRaw only required key->params to be set. Parameters
are populated by wc_LmsKey_SetParameters, well before wc_LmsKey_MakeKey
or an import produces a public key, so a caller that had merely selected
a parameter set received a buffer full of zeros and a success return.
Require the same OK, VERIFYONLY or NOSIGS state that
wc_LmsKey_ExportPub_ex already enforces, and cover the parameter-only
case in the LMS decision coverage test.

Fixes F-8150.
2026-09-11 17:44:32 +02:00
Marco Oliverio 49cd233790 dtls: cid: enforce tx CID size limit on DTLS 1.2 only 2026-09-11 13:28:29 +02:00
kaleb-himes e617424098 Add a version API for wolfEntropy and update dox 2026-09-10 11:48:34 -06:00
Tobias Frauenschläger ba8ab7069e cryptocb: let wc_KeyStore_Derive() request the key size
Derive is the only key store operation that creates a key without any way to
say how big it should be. Every other one has an answer: ImportPlain has the
plaintext's length, ImportWrapped reads it from the blob, the exports and
GetInfo report a property of a key that already exists. Derive has keyType,
which is a purpose rather than a length - AES is 128 or 256 either way -
derivSz, which measures the input rather than the output, and attrs, which is
three flag bits. So the device picks, the caller cannot ask, and GetInfo then
reports a size the API gave no way to request.

Add keySz, in bytes, beside the keyType it qualifies. Zero keeps the current
behaviour and leaves the choice to the device, which is the right answer for a
key store whose derivation has only one output size.

PKCS#11 carries this in C_DeriveKey's template as CKA_VALUE_LEN and PSA in the
attributes passed to psa_key_derivation_output_key(); this is the same
parameter under a name that matches wc_KeyStore_ImportPlain().

The key store API reached master without a ChangeLog entry. Add one here, since
this is the last change to that API and the entry can describe it as it ships.
2026-09-10 12:16:57 +02:00
Tobias Frauenschläger 032f115cae Fix Ed25519/Ed448 make_public documentation and test leftovers
wc_ed25519_make_public() and wc_ed448_make_public() take pubKeySz by
value, but every doxygen example passed its address.  Copying the example
gives "incompatible pointer to integer conversion", which is an error
rather than a warning on current compilers.

wc_ed25519_make_public() has kept the derived public key in the key object
since it started doing so, but its documentation still described a pure
derivation into the caller's buffer.  Mark the key argument [in,out] and
say what it stores, matching the Ed448 wording.

test_wc_SignCRL_ed25519() still set pubKeySet by hand after calling
wc_ed25519_make_public(), which has set it itself since the same change.
2026-09-10 11:30:02 +02:00
Tobias Frauenschläger 443bdb09f8 Store the derived public key in wc_ed448_make_public()
wc_ed448_make_public() wrote the derived point only into the caller's
output buffer while unconditionally setting key->pubKeySet, leaving
key->p all zeros. wc_ed448_sign_msg() gates on pubKeySet alone and hashes
key->p into the challenge, so a key that arrived without a public half -
a PKCS#8 v1 PrivateKeyInfo carries no public-key field - would sign over
an all-zero public key once make_public had been called on it. No
verifier accepts those signatures and nothing reports an error. Before
the make_public call the same key fails loudly with ECC_PRIV_KEY_E, so
deriving the public key turned a hard failure into silent corruption.

Adopt the derived key into the object when it did not already carry one,
matching wc_ed25519_make_public(). wc_ed448_check_key() is unaffected: it
requires pubKeySet before calling make_public, so its private-vs-public
comparison still runs against the stored key. wc_ed448_make_key() clears
pubKeySet before deriving, so make_public now does the copy into key->p
and key->k that make_key used to do itself.

Document the side effect in the Ed448 doxygen, in both the English and the
Japanese copy: the key argument is [in,out] now. Route
wc_ed448_import_private_key_ex() through the same helper, so the key buffer
layout has one definition, and record at the helper why it never overwrites
a public key the caller already set. test_wc_SignCRL_ed448() no longer sets
pubKeySet by hand.

The regression test exports the private key to check the public half
mirrored into key->k; without that check, dropping the copy left the test
green even though wc_ed448_export_private() would hand back a zeroed public
half. Only its signing round trip is gated on HAVE_ED448_SIGN and
HAVE_ED448_VERIFY, so the storage checks still run in a sign-less build.
2026-09-10 11:29:32 +02:00
David Garske 6314a051e9 Add crypto callback WC_PENDING_E support to wolfCrypt HKDF 2026-09-09 16:02:27 -07:00
David Garske 55d382777f ML-DSA: optional precomputed matrix A for verify on constrained targets 2026-09-08 16:29:14 -07:00
David Garske 39542cebe3 Add CHAR_BIT != 8 octet boundary helpers and fix the C28x SP regression 2026-09-08 16:29:14 -07:00
Sean Parkinson 36091dadf3
Merge pull request #11351 from miyazakh/f7401_hpke
Add Doxygen documentation for the HPKE public API
2026-09-08 08:55:44 +10:00
philljj ed61c5a778
Merge pull request #11333 from SparkiDev/tls_cert_vfy_tests
TLS certificate verification: add more tests
2026-09-07 12:20:53 -05:00
Tobias Frauenschläger b129dbb625 cryptocb: add WC_ALGO_TYPE_KEYSTORE for hardware key store operations
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.
2026-09-07 08:22:01 -07:00
philljj 339aa5779f
Merge pull request #11165 from SparkiDev/argon2
Argon2: Add Argon2d/i/id version 1.3
2026-09-03 09:51:30 -05:00
philljj 7fe91174a0
Merge pull request #11291 from gasbytes/persistent-session-cache-fix
Create the persisted session cache file with owner-only permissions
2026-09-03 09:32:13 -05:00
Sean Parkinson 23b33a2635 Argon2: Add Argon2d/i/id version 1.3
Add implementation of Argon2d/Argon2i/Argon2id.
Supports threading.
2026-09-03 15:51:38 +10:00
Sean Parkinson 411c3406c8
Merge pull request #11265 from kaleb-himes/PQ-FS-2026-Part3-SecurityReview-nofallback-E
PKCS callback typedef fixes and SLH-DSA standards updates
2026-09-03 15:15:14 +10:00
Sean Parkinson ccb11f354c
Merge pull request #11308 from Frauschi/curve25519-cryptocb-fix
Curve25519 CryptoCb fix
2026-09-03 15:08:20 +10:00
philljj 9a192651a6
Merge pull request #11215 from SparkiDev/tls13_rfc9846
Conformance to RFC 9846: New version of TLS 1.3 specification
2026-09-02 22:31:24 -05:00
lealem47 b7339b7583
Merge pull request #11271 from kaleb-himes/PQ-FS-2026-Part3-SecurityReview-nofallback-I
move wolfentropy outside the FIPS boundary and add example in dox for custom oe timer
2026-09-02 15:20:13 -04:00
Hideki Miyazaki 89af0d5c9b Addressed review comment 2026-09-02 09:52:09 -04:00
Hideki Miyazaki d8bb87805c Add Doxygen documentation for the HPKE public API 2026-09-02 08:03:19 -04:00
Tobias Frauenschlaeger 0fdf71079f Only offload a key-owned X25519 private scalar to that key's own device
wc_CryptoCb_Curve25519MakePub took no devId and resolved its device with a
lookup for INVALID_DEVID, falling back to the first registered device. Every
route to an X25519 public point derivation went through it, so a key bound to
one device had its private scalar offered to whichever device happened to be
registered first, with no way to opt out.

Give both wc_CryptoCb_Curve25519MakePub and wc_CryptoCb_Curve25519Generic a
devId parameter and let only a caller that selected no device settle for the
first registered one, matching the curve448 siblings. wc_curve25519_make_key
and wc_curve25519_export_public_ex now derive the point through a devId
carrying helper that reaches the callback only when the key names a device.
The keyless public API has no key to take a devId from, so it offers the
scalar to wc_CryptoCb_DefaultDevID() and keeps its old behaviour, while
honouring WC_NO_DEFAULT_DEVID.

Under WOLFSSL_CURVE25519_BLINDING both wc_curve25519_make_pub and
wc_curve25519_generic fall through to their blinded variant after the
callback declined, which dispatched the same private scalar to the same
device a second time. The fall-through now calls the software half of the
blinded derivation directly, so a declining device is offered the scalar
once.

Under WOLF_CRYPTO_CB_ONLY_CURVE25519 an unbound key passed to
wc_curve25519_export_public_ex now returns NO_VALID_DEVID rather than
reaching the first registered device. Such builds must create keys with
wc_curve25519_init_ex and a real devId.
2026-09-02 12:41:29 +02:00
Sean Parkinson c2b26fee3a
Merge pull request #11332 from yosuke-wolfssl/fix/f_12563
wolfio: drop the unreachable ISO-TP receive timeout branch
2026-09-02 16:59:17 +10:00
Sean Parkinson e8fac4e0e8 Conformance to RFC 9846: New version of TLS 1.3 specification
RFC 9846, 5.5
CheckTLS13AEADSendLimit(): at the AEAD limit while sending early data,
return TOO_MUCH_EARLY_DATA instead of calling Tls13UpdateKeys(). A KeyUpdate
there would go out pre-handshake.

RFC 9846, 6.1
Three alert sites in DoAlert() / DoProcessAlertRecord(): TLS 1.3
user_canceled is now exempt from teardown and session invalidation at any
AlertLevel, not just warning. TLS 1.2 unchanged.

RFC 9846, 4.7.3
New Tls13KeyUpdateLimitReached() helper shared by send and receive
paths. At the 2^48-1 cap, DoTls13KeyUpdate() drops a peer's update_requested
and continues, rather than failing the connection. App-initiated
wolfSSL_update_keys() still returns BAD_STATE_E.

RFC 9846, 4.3
TranslateErrorToAlert() maps BUFFER_E to decode_error as well as
BUFFER_ERROR — one case label covering 27 malformed-extension sites that
previously aborted with no alert sent.

Tests added.
2026-09-02 16:07:47 +10:00
Sean Parkinson 7bfdc9c793
Merge pull request #11301 from miyazakh/f6776_3des
Documents a precondition in the signle-DES API
2026-09-02 16:00:07 +10:00
Sean Parkinson 0e3155cece
Merge pull request #11283 from miyazakh/f9972_curve25519
Fix peer key masking
2026-09-02 15:54:01 +10:00
Sean Parkinson fdc454328c
Merge pull request #11162 from JacobBarthelmeh/afalg
Fixes for AF-ALG code paths and add CI test
2026-09-02 15:39:55 +10:00
Sean Parkinson 835a7c17c6 TLS certificate verification: add more tests
Add tests for different modes when doing certificate verification in TLS.
Update comments.
2026-09-02 07:31:27 +10:00
kaleb-himes ac9fff9280 Move wolfentropy outside the FIPS boundary for v7 2026-09-01 11:26:57 -06:00
kaleb-himes e8e0630c76 SLH-DSA pre-hash enforcement per FIPS 205 and FIPS v7 test fixes 2026-09-01 10:38:43 -06:00
Reda Chouk c8cc22cdbc wc_port: add wc_fopen_owner_only() and use it for the persisted session cache file 2026-09-01 17:02:15 +02:00
Yosuke Shimizu 8f9790e9fb wolfio: drop the unreachable ISO-TP receive timeout branch
- ISOTP_Receive() waits for the first frame in a loop that exits only
  on a non-zero result, and now handles just the negative case; the
  WOLFSSL_CBIO_ERR_TIMEOUT return is gone and a comment records that
  nothing times out between messages.
- The wolfSSL_SetIO_ISOTP() doxygen block states what recv_fn returns
  for a frame, for no frame within timeout, and for an error.

Issue: F-12563
2026-09-01 14:48:02 +09:00
philljj 0827c4bca6
Merge pull request #11268 from holtrop-wolfssl/f-8148
Return MISSING_KEY from wc_SlhDsaKey_Export* when key not present
2026-08-31 15:25:20 -05:00
philljj d71b4fa0c9
Merge pull request #11246 from danielinux/iotsafe-mutex
IoT-Safe: serialize APDU transactions with a port mutex
2026-08-31 11:00:19 -05:00
Hideki Miyazaki c4aee67cb9 Fixed the Doxygen in both language copies 2026-08-30 12:59:24 -04:00
Josh Holtrop 38690da0e1 Return MISSING_KEY from wc_SlhDsaKey_Export* when key not present
Fixes F-8148
2026-08-27 14:49:42 -04:00
Hideki Miyazaki 29e831e9ca Addressed review comments 2026-08-27 07:07:14 -04:00
Hideki Miyazaki e69491d0be Documents a precondition in the signle-DES API 2026-08-27 07:00:06 -04:00
David Garske 918a8b7e47 Require a key for 3DES ECB operations on all backends 2026-08-26 15:46:31 -07:00
Daniele Lacamera 62a5c4de4d IoT-Safe: make port initialization itself thread-safe by using static
mutex

Addressed comment by Fenrir reviewer. Removed lazy mutex initializer,
replaced with static mutex
2026-08-26 08:42:37 +02:00
Daniele Lacamera fa610dc3cb addressed copilot review
- iotsafe_init(): free the mutex on the ATE0 and drain failure paths
  so a retried init never double-initializes it
- guard every exported API entry (wc_iotsafe_*, wolfIoTSafe_GetCert_ex,
  wolfIoTSafe_GetRandom) against locking an uninitialized mutex via
  iotsafe_ensure_init(), which lazy-initializes the port before locking
- doxygen: wolfIoTSafe_SetCSIM_write_cb param rf -> wf
2026-08-26 08:42:37 +02:00
Daniele Lacamera 130d4996b6 IoT-Safe: serialize APDU transactions with a port mutex
All IoT-Safe operations share the file-scope static command/response
buffers on a single CSIM channel. Concurrent operations (e.g. a random
generation and an ECDSA sign callback from different TLS sessions)
could overwrite each other's buffers and consume the wrong modem
reply, corrupting cryptographic output or leaving the applet in a
persistent error state.

Add a port-level mutex (active in multi-threaded builds, no-op when
SINGLE_THREADED) held across each APDU transaction. The seven
single-transaction operations get thin serialized wrappers. GetRandom
locks after its lazy-init check, and the ECDH callback locks its APDU
branch, calling the locked impls directly since it already holds the
mutex (the software fallback never takes the lock). The mutex is
created in iotsafe_init(); document the single-threaded init contract
in the doxygen of wolfSSL_CTX_iotsafe_enable() and the CSIM callback
setters.

Fixes F-10045.
2026-08-26 08:42:37 +02:00
night1rider eb1cde51ab Address review findings on curve448 cryptocb support
Assert cryptocb output in curve448_onlycb_test, reject an all-zero
wc_curve448_generic result, guard the new API test for CB-only builds.
2026-08-21 17:04:18 -06:00
night1rider 3d7f7ad4d6 Add curve448 crypto callback support
Mirror curve25519: keygen, shared secret, make pub and generic
callbacks, wc_curve448_init_ex/new/delete, new wc_curve448_generic
API with scalar clamp checks, WOLF_CRYPTO_CB_ONLY_CURVE448 mode,
TLS devId plumbing, tests (test.c, api unit tests, swdev),
benchmark devId, CI entries.
2026-08-21 17:04:18 -06:00