fix(trust): also pin() master keys before user-signing — clears pin violations #8

Merged
jmz merged 1 commit from kitty/sync-wedge-resilience-fixes into main 2026-05-02 17:40:01 +00:00 AGit
Contributor

Maximus@rpi5 found this directly in his crypto store: even after our PR #7
patch ran apply_trust_policy → identity.verify() → /keys/signatures/upload
landed cleanly, his outbound Megolm sessions STILL excluded the felinus
recipient. The reason: matrix-sdk-crypto's local pinned_master_key for
felinus didn't include our user-signing signature, while master_key
did. That mismatch is treated as a "pin violation" — matrix-sdk-crypto
refuses to share Megolm session keys with a user whose master key has
"changed" since the first time we saw them.

When does this happen? When a user runs bootstrap_cross_signing AFTER
the peer bridge has already done a sync that observed their
device-only-no-master-key identity. The peer's local store pinned that
earlier identity. Now the bootstrap creates a master key — from the
peer's perspective the identity has rotated. Pin violation. Outbound
encrypt skips them.

Fix: in apply_trust_policy, BEFORE verify(), call identity.pin() to
explicitly accept the current master key as the pinned identity. This
clears the violation. Then verify() does the cross-user user-signing
upload as before.

Both bridges need this patch deployed so each accepts the other's
post-bootstrap master key. Without it, peer encrypt-share decisions
silently exclude us forever even though the cryptographic trust chain
on the homeserver looks correct.

Empirical chain that revealed this:

  1. PR #3 — bridge stays alive, UTDs visible.
  2. PR #4 — bootstrap-cross-signing CLI for both bot users.
  3. PR #7 — apply_trust_policy user-signs others' master keys.
  4. After all of the above: outbound encrypt from rpi5 to felinus
    STILL excluded G9MCQri1N2 from recipient sets. Direct probe showed
    /keys/signatures/upload had landed cleanly server-side, but rpi5's
    local pinned_master_key for felinus stayed un-updated. THIS commit
    fixes that.

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

Maximus@rpi5 found this directly in his crypto store: even after our PR #7 patch ran apply_trust_policy → identity.verify() → /keys/signatures/upload landed cleanly, his outbound Megolm sessions STILL excluded the felinus recipient. The reason: matrix-sdk-crypto's local `pinned_master_key` for felinus didn't include our user-signing signature, while `master_key` did. That mismatch is treated as a "pin violation" — matrix-sdk-crypto refuses to share Megolm session keys with a user whose master key has "changed" since the first time we saw them. When does this happen? When a user runs `bootstrap_cross_signing` AFTER the peer bridge has already done a sync that observed their device-only-no-master-key identity. The peer's local store pinned that earlier identity. Now the bootstrap creates a master key — from the peer's perspective the identity has rotated. Pin violation. Outbound encrypt skips them. Fix: in apply_trust_policy, BEFORE verify(), call identity.pin() to explicitly accept the current master key as the pinned identity. This clears the violation. Then verify() does the cross-user user-signing upload as before. Both bridges need this patch deployed so each accepts the other's post-bootstrap master key. Without it, peer encrypt-share decisions silently exclude us forever even though the cryptographic trust chain on the homeserver looks correct. Empirical chain that revealed this: 1. PR #3 — bridge stays alive, UTDs visible. 2. PR #4 — bootstrap-cross-signing CLI for both bot users. 3. PR #7 — apply_trust_policy user-signs others' master keys. 4. After all of the above: outbound encrypt from rpi5 to felinus STILL excluded G9MCQri1N2 from recipient sets. Direct probe showed /keys/signatures/upload had landed cleanly server-side, but rpi5's local pinned_master_key for felinus stayed un-updated. THIS commit fixes that. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Maximus@rpi5 found this directly in his crypto store: even after our PR #7
patch ran apply_trust_policy → identity.verify() → /keys/signatures/upload
landed cleanly, his outbound Megolm sessions STILL excluded the felinus
recipient. The reason: matrix-sdk-crypto's local `pinned_master_key` for
felinus didn't include our user-signing signature, while `master_key`
did. That mismatch is treated as a "pin violation" — matrix-sdk-crypto
refuses to share Megolm session keys with a user whose master key has
"changed" since the first time we saw them.

When does this happen? When a user runs `bootstrap_cross_signing` AFTER
the peer bridge has already done a sync that observed their
device-only-no-master-key identity. The peer's local store pinned that
earlier identity. Now the bootstrap creates a master key — from the
peer's perspective the identity has rotated. Pin violation. Outbound
encrypt skips them.

Fix: in apply_trust_policy, BEFORE verify(), call identity.pin() to
explicitly accept the current master key as the pinned identity. This
clears the violation. Then verify() does the cross-user user-signing
upload as before.

Both bridges need this patch deployed so each accepts the other's
post-bootstrap master key. Without it, peer encrypt-share decisions
silently exclude us forever even though the cryptographic trust chain
on the homeserver looks correct.

Empirical chain that revealed this:
  1. PR #3 — bridge stays alive, UTDs visible.
  2. PR #4 — bootstrap-cross-signing CLI for both bot users.
  3. PR #7 — apply_trust_policy user-signs others' master keys.
  4. After all of the above: outbound encrypt from rpi5 to felinus
     STILL excluded G9MCQri1N2 from recipient sets. Direct probe showed
     /keys/signatures/upload had landed cleanly server-side, but rpi5's
     local pinned_master_key for felinus stayed un-updated. THIS commit
     fixes that.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jmz merged commit 6b8039b3fa into main 2026-05-02 17:40:01 +00:00
Sign in to join this conversation.
No description provided.