Skip to content

fix(sdk): DSPX-1561 hash assertions as received - #437

Draft
dmihalcik-virtru wants to merge 1 commit into
DSPX-1561-strict-manifestfrom
DSPX-1561-assertion-hash
Draft

dmihalcik-virtru wants to merge 1 commit into
DSPX-1561-strict-manifestfrom
DSPX-1561-assertion-hash

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Proposed Changes

  • Each assertion keeps the JSON object it was parsed from. The assertion hash covers that object minus only its top-level binding (ZTDF assertions specification, Section 4), never a re-serialization of the typed model, so members the SDK doesn't model and the JSON type of statement.value are covered.
  • Serializing a manifest writes each assertion back as received; changing a typed field replaces only that member.
  • New public Manifest.Assertion.computeAssertionHash(String) returns the hash for one raw assertion, applying the Section 3 parsing rules first.
  • Writers hash the wire form they write, emit binding method jws, and refuse with IllegalArgumentException (a configuration error, not a tamper error) an assertion that readers would reject, or one without an id.
  • id and binding are read leniently, so verification, not parsing, reports a bad value. A recomputed hash or assertionSig that doesn't match is reported as SDK.AssertionFailureException with binding-mismatch.

Stacked on: #436.
Split out of #432 (draft; the complete change). Cross-SDK counterparts: opentdf/platform#4306, opentdf/web-sdk#1140.

Compatibility: assertions are verified against the hash of their stored form. A file whose writer hashed a different form fails verification.

Checklist

  • I have added or updated unit tests
  • I have added or updated integration tests (if appropriate)
  • I have added or updated documentation

Testing Instructions

  • mvn -pl sdk,cmdline -am test (new cases in AssertionHashTest, including the spec Section 4.4 worked examples; round-trip cases in StrictManifestParsingTest; writer cases in TDFTest).

Each assertion keeps the JSON object it was parsed from. assertionHash is
computed over that object minus only its top-level binding, as Section 4
of the ZTDF assertions specification defines it, never over a
re-serialization of the typed model, so members this SDK does not model
and the JSON type of statement.value are covered. The object is written
back unchanged when a manifest is serialized; changing a typed field
replaces only that member. The id and binding members are read
leniently, so that verification, not parsing, reports a bad value.

Writers hash the wire form they write, emit binding method "jws", and
refuse, as a configuration error, an assertion that a reader would
reject while parsing or that has no id.

Add the public Manifest.Assertion.computeAssertionHash(String), which
applies the Section 3 parsing rules to the raw JSON of one assertion and
returns its hash. A recomputed hash or assertionSig that does not match
the signed one is reported as an AssertionFailureException with
binding-mismatch.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
@coderabbitai

coderabbitai Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant