a07e22d7ab
openmls (via mdk-core) strict-verifies both the FramedContentAuthData
signature and the membership_tag on every inbound PublicMessage from a
Member sender (RFC 9420 §6.1, §6.2). Quartz was framing commits with
empty placeholders for both fields, so any existing member processing a
quartz-originated commit tripped `openmls::ciphersuite: Incompatible
values` (constant-time compare of a zero-length tag against the 32-byte
expected HMAC). That's the reason every interop test that requires B to
process a commit from amy (add-member, rename, remove, leave, promote,
catchup) was failing at step one.
Fix computes both fields correctly:
* capture pre-commit groupContext bytes, membership_key, and
signingPrivateKey before the key schedule / epoch advance
* build FramedContentTBS = version || wire_format || FramedContent ||
serialized_context and SignWithLabel("FramedContentTBS", ..) with
the committer's pre-commit leaf signing key
* build AuthenticatedContentTBM = TBS || signature<V> ||
confirmation_tag<V> and HMAC-SHA256 it with the pre-commit
membership_key
No change to quartz's own processCommit path (it doesn't re-verify these
fields on inbound), so this is a one-way fix for outbound to openmls
peers.
https://claude.ai/code/session_016kAxdp6ubB5CnF9URhCEzP