Fix TSP message imprint algorithm/digest length consistency - #11153
Fix TSP message imprint algorithm/digest length consistency#11153yosuke-wolfssl wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a correctness/security issue in the RFC 3161 TSP messageImprint handling by making the digest length consistently derived from the configured hash algorithm, and by ensuring encoders fail closed when a digest was never provided or is the wrong length.
Changes:
- Tighten
TspRequestsetter semantics:SetHashType()now invalidates any previously-set digest, andSetHash()requires an algorithm to be set and enforces the expected digest length. - Add encoder-side validation in
wc_TspRequest_Encode()andwc_TspTstInfo_Encode()to reject missing digests and determinable length mismatches. - Update documentation and extend API tests to cover the previously unsafe/ambiguous configurations (forgotten digest, wrong length, and call-order interactions).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| wolfcrypt/src/tsp.c | Updates requester/responder imprint setters to enforce algorithm-before-digest and digest-length consistency. |
| wolfcrypt/src/asn_tsp.c | Adds fail-closed encode-time imprint length validation based on the algorithm’s digest size when determinable. |
| tests/api/test_tsp.c | Adds/updates tests covering missing digest, setter ordering, and length mismatch behaviors. |
| doc/dox_comments/header_files/tsp.h | Updates public API documentation/examples to use the setters and document the ordering/length contract. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11153
Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src
Findings: 3
3 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Findings are non-blocking.
b909144 to
d4ae753
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (2)
doc/dox_comments/header_files/tsp.h:56
- This doc example passes
sizeof(hash)intowc_TspRequest_SetHash()even though the API expects aword32. Other examples in this file castsizeof(...)toword32, so doing the same here keeps the documentation consistent and avoids potential conversion warnings for users compiling with strict flags.
wc_TspRequest_Init(&req);
wc_TspRequest_SetHashType(&req, WC_HASH_TYPE_SHA256);
wc_TspRequest_SetHash(&req, hash, sizeof(hash));
req.certReq = 1;
doc/dox_comments/header_files/tsp.h:23
- In the documentation examples,
wc_TspRequest_SetHash()takes aword32size but the example passessizeof(hash)(asize_t). Elsewhere in this same doc file sizes are explicitly cast toword32(e.g.,word32 hashSz = (word32)sizeof(hash);), so keeping the cast here avoids signed/size conversion warnings in downstream builds.
This issue also appears on line 53 of the same file.
wc_TspRequest_Init(&req);
wc_TspRequest_SetHashType(&req, WC_HASH_TYPE_SHA256);
wc_TspRequest_SetHash(&req, hash, sizeof(hash));
req.certReq = 1;
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11153
Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src
Findings: 3
2 finding(s) posted as inline comments (see file-level comments below)
Low (1)
Stale SHA-512/224/256 skip in wc_OidGetHash round-trip coverage
File: tests/api/test_hash.c:1109
Function: test_wc_HashFeatureCoverage
Category: Missing edge-case coverage on a function the PR also changed
The comment claims wc_OidGetHash() has no case for SHA512_224h/SHA512_256h, which this PR makes false, and the guard still skips the wc_HashGetOID → wc_OidGetHash round-trip assertion for exactly the two mappings the PR adds. supportedHash[] only contains those types when the mapping is present (!HAVE_FIPS && !HAVE_SELFTEST), so the skip is now permanently dead.
Recommendation: Drop the two SHA512_224/SHA512_256 exclusions and the stale comment so the round trip is asserted for every entry of supportedHash[].
Referenced code: tests/api/test_hash.c:1109-1113 (5 lines)
This review was generated automatically by Fenrir. Findings are non-blocking.
d4ae753 to
d2ffa65
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11153
Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfssl-bugs
Failed targets: wolfcrypt-src, wolfssl-src
Problem
f-7075: theTspRequestmessage imprint was configured by two setters that both wroteimprint.hashSzwith no cross-validation, so the field did not distinguish "a digest was supplied" from "the algorithm implies this length".wc_TspRequest_Init()+wc_TspRequest_SetHashType(WC_HASH_TYPE_SHA256)lefthashSz = 32withimprint.hashstill all zero.wc_TspRequest_Encode()only checkedhashSz == 0, so it returned 0 and encoded a TimeStampReq whose messageImprint was 32 zero bytes — the caller obtains a token over a fixed, attacker-known digest instead of over their data.SetHash(sha1Digest, 20)thenSetHashType(SHA-256)raisedhashSzto 32, encoding 20 real bytes plus 12 zero bytes tagged SHA-256; the reverse order encoded a 20-byte imprint tagged SHA-256. Neither was rejected.wc_TspTstInfo_SetMsgImprint()andwc_TspTstInfo_Encode()had the samehashSz != 0-only check. Medium severity, unsafe default configuration. TSP is unreleased (added after v5.9.2), so the setter contract is tightened rather than kept compatible.Fix (
wolfcrypt/src/tsp.c,wolfcrypt/src/asn_tsp.c,wolfcrypt/src/hash.c)hashSznow means only "a digest was supplied"; the expected length is derived fromimprint.hashAlgOIDviawc_HashGetDigestSize(wc_OidGetHash(...)). No new struct member, no ABI change.wc_TspRequest_SetHashType()imprint.hashzeroed,hashSz = 0) instead of resizing itwc_TspRequest_SetHash()HASH_TYPE_Ewhen the algorithm is unset/unavailable,BUFFER_EwhenhashSzis not its digest sizewc_TspTstInfo_SetMsgImprint()BUFFER_Eon a length mismatch; lenient for an unknown/unavailable OID so a TSA can echo an imprint it cannot computewc_TspRequest_Encode(),wc_TspTstInfo_Encode()hashSz == 0(never-supplied digest) and a determinable length mismatchwc_OidGetHash()SHA512_224h/SHA512_256hcases so those digest lengths are determinableThe length check applies only when the digest size is determinable, so an unknown OID still yields
ASN_UNKNOWN_OID_E. Decoders are unchanged: a verifier still sees what arrived, and a malformed imprint fails closed atwc_TspTstInfo_Encode()/wc_TspTstInfo_CheckRequest(). The OpenSSL compat layer writes the imprint fields directly, so order-independentTS_MSG_IMPRINT_set_algo/_set_msgsemantics are preserved and it gains only the fail-closed encode check.The
wc_OidGetHash()gap came out of review:wc_HashGetOID()has mapped those hash types to those OIDs since #4257 (2021), but the reverse function, written in 2018, was never updated. Deriving the expected length through it therefore made SHA-512/224 and SHA-512/256 imprints unbuildable (SetHash()always returnedHASH_TYPE_E) and silently skipped the encode-time length check for them. The two cases use guards mirroringwc_HashGetOID(); being the shared reverse lookup, this also unbreaks those algorithms for PKCS#7/CMS digest algorithms, OCSP CertID hashes, the PKCS#12 MAC, and the OpenSSL-compat RSA-PSS path.Closes
f-7075.Tests
tests/api/test_tsp.c: forgotten digest fails to encode;SetHash()thenSetHashType()discards the digest and fails to encode;SetHash()with no algorithm →HASH_TYPE_E; wrong length →BUFFER_Efor both setters; encode-time length mismatch for request and TSTInfo; SHA-512/224 imprint set and encoded end to end.tests/api/test_hash.c: both OIDs added to the supported and not-supported lists oftest_wc_OidGetHash().The SHA-512/224 case is gated on the same condition
wc_HashGetDigestSize()uses for that algorithm —(!HAVE_FIPS || FIPS_VERSION3_GE(7,0,0)) && !HAVE_SELFTESTon top of theWOLFSSL_SHA512/WOLFSSL_NOSHA512_224checks — so it is never compiled into a build wherewc_TspRequest_SetHashType()reports the algorithm unavailable.Verification
-Werror. Also builds clean withWOLFSSL_TSP_REQUESTERalone,WOLFSSL_TSP_RESPONDERalone, and-DWOLFSSL_NOSHA512_224 -DWOLFSSL_NOSHA512_256.make check: 6 passed, 4 skipped, 0 failed (includesscripts/tsp.testand the fullunit.test).tsp59/59,ossl_tsp18 passed,hash13 passed.hashSz = digestSzfails the forgotten-digest test; dropping the encode length term fails both mismatch tests; removing theSHA512_224hcase fails the new SHA-512/224 andwc_OidGetHash()tests.