Commit Graph

418 Commits (master)

Author SHA1 Message Date
David Garske 41bf939642 Skip the fwTPM RSA-PSS unit tests when wolfSSL is built without PSS 2026-11-03 13:03:11 -08:00
Eric Blankenhorn a014f2b4b0
Merge pull request #656 from dgarske/fwtpm_fixes
Fixes for Firmware TPM issues and related session, clock and signature defects
2026-11-03 11:57:45 -05:00
David Garske e65848fde9 fwtpm: gate ECC DHKEM on HAVE_HKDF 2026-11-02 14:04:22 -08:00
David Garske 25ee20e266 swtpm: keep waiting for a UART response until the cumulative timeout 2026-11-02 12:36:26 -08:00
David Garske 85c4ba40c4 Parse parameters after the authorization area in all fwTPM handlers 2026-11-02 12:12:23 -08:00
David Garske 31340d600d Report the fwTPM Sign digest size error on parameter 1 2026-11-02 12:12:23 -08:00
Aidan Garske a5c09d56d9 Report fwTPM capabilities with durable clock and orderly state 2026-11-02 12:12:23 -08:00
Aidan Garske 53d6e9f817 Fix fwTPM Hash and StirRandom parameter handling 2026-11-02 12:12:23 -08:00
David Garske 0f67862949 Verify HMACs of all fwTPM sessions in the authorization area 2026-11-02 12:12:23 -08:00
Aidan Garske b4a609121e Include entity authorization in fwTPM parameter encryption 2026-11-02 12:12:23 -08:00
Aidan Garske 63cc2e95e1 Include fwTPM sequence handles in capability queries 2026-11-02 12:12:23 -08:00
Aidan Garske 9c9faaeed2 Normalize ECC signature scalars across signing wrappers 2026-11-02 12:12:23 -08:00
Aidan Garske 58dd09fb22 Restore and validate protected fwTPM contexts 2026-11-02 12:12:23 -08:00
Aidan Garske 40cc20b89c Validate fwTPM TestParms and report parameter errors 2026-11-02 12:12:22 -08:00
Aidan Garske 0a50945504 Align fwTPM RSA hashes and algorithm capabilities 2026-10-29 08:01:19 -07:00
Aidan Garske 3ff7ad4478 Pad fwTPM ECDSA scalars and handle all-zero digests 2026-10-29 08:01:19 -07:00
Eric Blankenhorn c5a655311e fwtpm: size RSASSA DigestInfo buffers for SHA-512, check Sign digest size
FwSignDigestAndAppend and FwVerifySignatureCore sized their PKCS#1
v1.5 DigestInfo buffers as WC_MAX_DIGEST_SIZE + MAX_ENCODED_DIG_ASN_SZ,
which leaves out the outer SEQUENCE and the AlgorithmIdentifier. A
SHA-512 DigestInfo is 83 bytes. Size both buffers with
MAX_DER_DIGEST_SZ, the constant wolfCrypt uses for this encoding.

- Reject TPM2_Sign with TPM_RC_SIZE when the digest size does not
  match the resolved scheme hashAlg (Part 3 Sec.20.2.1), matching
  FwCmd_SignDigest.
- examples/pcr/policy_sign: size the DigestInfo buffer with
  WOLFTPM_MAX_DER_DIGEST_SZ, since older wolfSSL does not export
  MAX_DER_DIGEST_SZ.
- tests: add RSASSA-SHA512 Sign/VerifySignature and Sign digest-size
  mismatch tests, run the SignDigest RSA roundtrip with SHA-512 too,
  and move BuildRsa2048SignPrimary out of the WOLFTPM_V185 block so
  builds without v1.85 can use it.
2026-10-27 11:03:49 -05:00
David Garske 17097f4771 nv: support owner/platform hierarchy auth in NV read/write wrappers 2026-10-23 12:07:57 -07:00
David Garske 0f51156bb6 asn: return X.509 issuer and subject and add TPM2_ASN_GetNameAttr 2026-10-22 19:44:56 -07:00
David Garske ca6d986a66
Merge pull request #642 from deadcaf3/worktree-fix-slot-overwrite
Keep slot-1 session in SignSequenceComplete
2026-10-22 09:25:02 -07:00
David Garske 195dd15ffa
Merge pull request #643 from deadcaf3/worktree-check-seed-exists
fwtpm: reject ML-DSA signing with no private seed
2026-10-22 09:24:22 -07:00
deadcafe 3db79c0ab3
Test policy-auth SignSequenceComplete slot 1
Cover the policyAuth branch: sign with a PolicyAuthValue-only ML-DSA
key whose policy session sits in slot 1, then assert the session
handle stays, its nonceTPM advances, and a second policy + sign on the
same session succeeds. The session is bound so the wrapper's
PolicyAuthValue HMAC key has a session key in front of the authValue.
2026-10-22 04:32:39 +05:30
David Garske 176c28f9b0
Merge pull request #644 from deadcaf3/fix-asn-trimzeros
Fix TPM2_ASN_TrimZeros skipping bytes
2026-10-21 16:00:47 -07:00
deadcafe 5be741380c
Skip slot-1 session test when signing unsupported
When the TPM rejects SignSequenceStart, the sign helper sets sigSz to
zero and returns. The slot-1 session checks still ran, and with a
free slot 2 the nonce assertion failed because nothing advanced the
nonce, aborting the suite. Unload the key and return once the first
sign produces no signature.
2026-10-22 00:18:12 +05:30
deadcafe d8206b8bc4
Fix TPM2_ASN_TrimZeros skipping bytes
The loop advanced both idx and the in pointer, so each check after the
first read two bytes past the intended one. An ECDSA R or S starting
00 <0x80 00 <0x80 lost a significant byte, and wolfTPM2_PK_EccSign then
DER-encoded a wrong signature that the TLS peer rejected (-330).

Only advance idx and return in + idx. Add a unit test using the S bytes
from the failing CI run.
2026-10-22 00:04:00 +05:30
deadcafe 65decab4fc
Clear bound Name when moving session to slot 2
The slot-1 session copied into slot 2 kept its Name. For a session
bound to that entity (name == bindName), TPM2_ParamEncBindKey() then
appended the bind authValue to the parameter-encryption key, but slot
2 authorizes no handle, so the TPM used the session key alone. The
command HMAC still validated, while the TPM decrypted the message to
other bytes and signed those.

Clear the Name in slot 2 and put the caller's Name back on restore,
unless the response retired the session. Add a bound-session
regression that verifies the signature over the original message.
2026-10-22 00:03:21 +05:30
deadcafe 5c08a963cd
Guard slot-1 restore for policy and 1-slot builds
- With MAX_SESSION_NUM=1 (--enable-smallstack --disable-wolfcrypt)
  the slot-1 save and restore read and wrote past dev->session.
  Compile them only when a second slot exists.
- A policy-auth key keeps its policy session in slot 1 and the
  command advances its nonce; restoring the snapshot rolled that
  nonce back. Skip the save and restore for policyAuth keys.
- With MAX_SESSION_NUM=2 the session cannot move to slot 2, so its
  nonce does not roll. Check the rolled nonce only when slot 2
  exists.
2026-10-21 23:40:05 +05:30
deadcafe c9a169ba86
fwtpm: reject ML-DSA signing with no private seed
SignSequenceComplete and SignDigest signed with obj->privKey without
checking that a private seed was loaded. For a public-only ML-DSA or
Hash-ML-DSA key from TPM2_LoadExternal they returned success with a
signature from the all-zero seed, which does not verify against the
key's public area.

Return TPM_RC_KEY when privKeySize is not MAX_MLDSA_PRIV_SEED_SIZE,
matching FwSignAttestMldsa. For sequences the check is in Complete,
where the key is used: the object at keyHandle can differ from the one
given to Start while keeping the same Name.
2026-10-21 23:39:29 +05:30
deadcafe dacb7eff55
Keep slot-1 session in SignSequenceComplete
wolfTPM2_SignSequenceComplete authorizes keyHandle with
wolfTPM2_SetAuthHandle(dev, 1, ...), which resets session slot 1 to
password auth. A caller's parameter-encryption HMAC session in slot 1
was silently dropped, so the next command (e.g. wolfTPM2_Decapsulate)
returned its secret unencrypted and the session's rolling nonce was
lost.

Save slot 1 before the command and restore it afterwards. When the
saved session is an HMAC session and slot 2 is free, run it from slot
2 for this command, where the TPM takes extra encrypt and audit
sessions, so it also protects the sign. Copy it back with the nonces
the command advanced.

Authorizing the key through the slot-1 session instead would fail
with TPM_RC_AUTH_FAIL for keys with an authValue, since an unbound
HMAC session does not carry the key's authValue.

Extend the ML-DSA key-auth sign test to sign with an HMAC session in
slot 1, check the session is kept and its nonce rolled, and verify the
signature through the same session.
2026-10-21 23:20:19 +05:30
David Garske 1976facacc Size RSA 4096 buffers and reject truncated public names 2026-10-20 20:03:48 -07:00
David Garske fe01b8ee09
Merge pull request #638 from Frauschi/cryptocb-key-ids
Resolve CryptoCb key ids as TPM handles
2026-10-20 11:01:15 -07:00
Aidan Garske 579c9a1c2c
Merge pull request #628 from dgarske/infineon_submodule
Infineon OPTIGA SLB9678 support over the TCG SPDM binding
2026-10-20 10:56:29 -07:00
David Garske ffd65ed7a6 fwtpm: fix Coverity CIDs 915121-915130 2026-10-20 10:32:32 -07:00
David Garske 5b60a8320c Add Infineon SLB9678 SPDM support on the wolfSPDM submodule 2026-10-20 10:22:25 -07:00
David Garske ebafd10c3e
Merge pull request #632 from aidangarske/fenrir-fixes-14017-15792
Harden fwTPM state handling
2026-10-20 10:11:29 -07:00
Aidan Garske 72d0345179 F-16123 - Refuse encryptedDuplication export without a new parent 2026-10-20 09:44:58 -07:00
Aidan Garske b25fa26366 F-16122 - Withhold hash tickets for TPM-generated data and HMACs 2026-10-20 09:44:58 -07:00
Aidan Garske e6ccc3ce01 F-16121 - Require authValue proof for policy sessions with an empty HMAC 2026-10-20 09:44:58 -07:00
Tobias Frauenschlaeger 15b881a107 Skip the v1.85 unit tests on a TPM without them
tests/unit_tests.c skips a v1.85 test when the TPM answers TPM_RC_VALUE,
TPM_RC_SCHEME or TPM_RC_COMMAND_CODE, but the checks could not match.
tpm2_asn.h defines TPM_RC_VALUE as its deprecated ASN alias (-203) unless
WOLFTPM_NO_DEPRECATED_ASN_RC is set, so every TPM_RC_VALUE check in the
file compared against an ASN error. A TPM without v1.85 rejects an ML-DSA
or ML-KEM template with TPM_RC_TYPE, which no check accepted, and a
response code carrying parameter bits never matched exactly. A build with
v1.85 therefore aborted the suite at the first PQC test against such a
TPM.

The test file opts out of the ASN aliases, so the existing checks compare
against the response code. Where a v1.85 key is created,
TEST_V185_UNSUPPORTED skips only when the creation failed and the TPM does
not list the algorithm in TPM_CAP_ALGS, so on a TPM with v1.85 a creation
failure still fails the test; test_alg_supported moves up for that. The
checks that run after the key exists drop TPM_RC_VALUE, which only ever
matched the ASN alias there, and keep their other codes, so a failure of
an algorithm the TPM has shown it supports is not taken for a missing
feature. Against a fwTPM built without v1.85 the suite now runs to the
end; against one with v1.85 the results are unchanged.
2026-10-19 20:00:14 +02:00
Tobias Frauenschlaeger 355ec2cb5e Resolve CryptoCb key ids as TPM handles
wolfTPM2_CryptoDevCb ignored the id of a wolfCrypt key and always used the
single ECDSA, RSA or ML-DSA key configured in TpmCryptoDevCtx. An
application that names its keys by id, such as
wolfSSL_CTX_use_PrivateKey_Id or wolfCert's key_id, could not keep more
than one key per type in the TPM, and EC key generation with a slot
already loaded returned that key's public half instead of a new key.

An ECC, RSA or ML-DSA key whose id is 4 bytes and, read big-endian, a
persistent or transient handle now names that TPM key, so a key blob
loaded with wolfTPM2_LoadKey is usable through the handle the TPM gave it.

Key generation with an id creates a fixedTPM, fixedParent key under
storageKey with an empty auth value and noDA, since a key id carries no
auth. A persistent handle must be free, and the key is persisted there
with EvictControl, which needs an empty owner authorization. The new id
WOLFTPM2_KEYID_TRANSIENT (0x80000000) leaves the key loaded at the
transient handle the TPM picks and writes that handle back into the id;
the caller unloads it with wolfTPM2_UnloadHandle. Any other id, an RSA
size the export cannot hold, and a wolfCrypt key that already holds a key
fail key generation instead of falling back to the slot or to software,
and so does a curve shorter than its hash (P-192 and P-224 with SHA-256),
whose every signature the signing path would refuse.
The last one matters because the TPM may itself pick 0x80000000 for a
generated key, and a second keygen on that wolfCrypt key would then create
another one and leave the first unreferenced.

Signing, RSA private, public and get-size operations read the key at the
handle and fail when it does not fit the request: a different type, a
restricted key such as a storage key, an RSA key with a padding scheme
or without decrypt, an ECC key with a scheme other than ECDSA or on
another curve, an ML-DSA key of another parameter set, or a wolfCrypt
key holding a public key other than the TPM key's or only a private key.
An RSA public key must match in both modulus and exponent, with a TPM
exponent of 0 read as 65537. ECDSA signing also fails when the key's
fixed scheme hash is shorter than the input or longer than the curve,
because the TPM fits the input to that hash and the signature would not
verify. Otherwise an ML-DSA request naming a HashML-DSA key would return
that key's signature as success, and a transient handle the TPM handed
to another key would sign for it. A key with the NULL scheme signs ECDSA
with the curve's hash under the same check; the hash is set explicitly
because the parsed public area carries none for a NULL scheme.
wolfTPM2_ReadPublicKey now zeroes its output, so that field no longer
holds stack contents. A build without HAVE_ECC_KEY_EXPORT or
WOLFSSL_MLDSA_PUBLIC_KEY cannot compare the public key, so it refuses a
wolfCrypt key that holds one. Public RSA operations on an RsaKey without
a modulus run on the TPM key, since an RsaKey named by id has none;
wolfSSL needs them to check its own RSA signature in TLS. An RsaKey with
a modulus keeps using it. The doxygen note lists these requirements,
including that a key named by id is used with an empty authorization
value, that an id-named ML-DSA key needs wc_MlDsaKey_SetParams, and that
without a public key in the wolfCrypt key a transient id names whatever
key is loaded at the handle.

A 4-byte id that only reads as a handle in little-endian order fails
instead of reaching the slot. Ids of any other length or value keep the
slot behaviour for signing, so the 8-byte ML-DSA placeholder id in the TLS
example is unaffected. wolfSSL passes a seeded ML-DSA key generation as
WC_PK_TYPE_PQC_SIG_KEYGEN_SEED, which the callback leaves to software.
ML-DSA key generation by id needs a wolfSSL with ML-DSA key generation.

Failures on these paths reach wolfCrypt as WC_HW_E. A positive TPM_RC
would be taken as a signature length by wolfSSL's certificate signing.

test_wolfTPM2_CryptoDevCb_KeyId and test_wolfTPM2_CryptoDevCb_MlDsaKeyId
generate keys by id against the TPM, sign with id-only keys, verify in
software, and check that a missing handle, a missing storage key, an
occupied handle, a curve mismatch and an id naming a key of another type
or ML-DSA parameter set are refused. They and
test_wolfTPM2_CryptoDevCb_TransientKeyId also cover transient key
generation and its write-back, signing through a loaded key blob,
unloading, a public key mismatch for ECC, RSA and ML-DSA, a wolfCrypt key
holding only a private key for ECC and ML-DSA, RSA public operations with
the RsaKey's own modulus, refusal of byte-swapped, short and other
transient ids, and refusal of keygen into a key that already holds one.
test_wolfTPM2_CryptoDevCb_KeyIdRefused names a restricted RSA storage
key, an RSA key with the OAEP scheme, a sign-only RSA key, an ECDH key
and a P-256 key with ECDSA-SHA384 by id and checks that each is refused,
that an RSA key created with exponent 0 signs for its public key, that a
P-256 key with the NULL scheme signs a hash that verifies, that a P-384
key with ECDSA-SHA256 refuses a SHA-384 input and signs a SHA-256 one
that verifies, and that RSA key generation above
WOLFTPM2_WRAP_RSA_KEY_BITS leaves no transient key behind, as does P-224
key generation when wolfSSL has P-224. The transient test also refuses
an RsaKey holding the TPM modulus with another exponent. The ML-DSA key
id test needs wolfSSL ML-DSA key generation and level 65, and checks
level 87 only when built in. The ML-DSA test skips on a TPM without
ML-DSA, and the persistent handle tests skip with the Windows TBS
interface, which blocks EvictControl. The tests that create an RSA key
in the TPM skip on a small-stack fwTPM build, whose reduced response
buffer cannot hold an RSA Create response.
2026-10-19 20:00:14 +02:00
Tobias Frauenschlaeger 18d49ddfc7 Stream ML-DSA signing input longer than one TPM buffer
wolfTPM2_CryptoDevCb passed the whole message to SignSequenceComplete and
rejected anything longer than MAX_DIGEST_BUFFER with BAD_FUNC_ARG. That
blocks certificate and CSR signing with a TPM ML-DSA key, since the signed
body carries the 1.3 to 2.6 KB public key. Input beyond one buffer now goes
through SignSequenceUpdate before the final SignSequenceComplete; input that
fits is still sent in one Complete.

The ML-DSA sign test drops the over-size BAD_FUNC_ARG case and signs a
message of two buffers plus 100 bytes, verified with a TPM verify sequence.
2026-10-19 15:50:37 +02:00
Aidan Garske 5f410f89a7 F-15744 - Require blinded ZGen multiplication 2026-10-16 14:12:12 -07:00
Aidan Garske effbc4a35e F-14681 - Reject mismatched object policies 2026-10-16 14:12:12 -07:00
Aidan Garske c01d55a2f1 F-14023 - Preserve crypto allocation errors 2026-10-16 14:12:12 -07:00
Aidan Garske a739024242 F-14024 - Preserve journal MAC allocation errors 2026-10-16 14:12:11 -07:00
Aidan Garske 2b42a1bc57 F-14017 - Reject malformed NV journal entries 2026-10-16 14:12:11 -07:00
Aidan Garske 334c6d0850 Address PR 629 review 2026-10-16 12:49:16 -07:00
Aidan Garske 2272ac6653 Rebase policy timeouts across Clear 2026-10-16 11:47:19 -07:00
Aidan Garske f12078f90e F-15835 - Validate PCR selection sizes 2026-10-16 11:47:19 -07:00
Aidan Garske 8c1b7f0b42 F-15832 - Enforce PolicySigned expiration 2026-10-16 11:47:19 -07:00