An unproven key replacement says so #176

Merged
paulhitt merged 1 commits from fix/an-unproven-key-replacement-says-so into main 2026-09-22 19:20:50 +00:00
paulhitt commented 2026-09-22 18:42:43 +00:00 (Migrated from gitlab.com)

The relay separates a device key replacement the old key signed for, rotate, from one that arrived with no signature at all, rotate_unproven, and keeps them apart in the log on purpose. IdentityRotation.report says why: "a client watching the log can tell this apart from a rotation the previous key vouched for."

No client could. Both kinds fell to the default branch and read "Their key set changed", the same sentence a routine change gets, so the distinction the relay records reached nobody. iOS describeKeyChange and Android Trust.kt were the same code in two languages, so this was not a parity gap: both were wrong identically.

The unproven case is the one that matters. It is exactly what somebody who cannot sign with the old key would produce.

Both kinds now name themselves, and the unproven one carries a warning that says what to do about it:

A device key was replaced on 29 Aug 2026, 12:00. The key it replaced did not sign for it. A replacement made by the person you are talking to normally does, so compare your safety number before you trust this one.

The warning is a separate sentence after the date, so the clause naming the day stays intact and the existing exact-string tests are untouched.

On the tests. One is a control: a test that only checked the unproven wording would pass if rotate were given the identical warning, which would be its own bug, so the two are asserted to differ. The Android side additionally pins its sentence against the iOS text, because two apps quietly drifting apart on a security warning is the failure this check exists to prevent.

Found by tracing row 5 of the audit readiness sweep. Same class as §19.3, §6.26, §6.23/§6.24 and §6.27: built on one side, unwired on the other, with a comment asserting a property nothing delivered.

Generated with Claude Code.

The relay separates a device key replacement the old key signed for, `rotate`, from one that arrived with no signature at all, `rotate_unproven`, and keeps them apart in the log on purpose. `IdentityRotation.report` says why: *"a client watching the log can tell this apart from a rotation the previous key vouched for."* **No client could.** Both kinds fell to the default branch and read "Their key set changed", the same sentence a routine change gets, so the distinction the relay records reached nobody. iOS `describeKeyChange` and Android `Trust.kt` were the same code in two languages, so this was not a parity gap: both were wrong identically. The unproven case is the one that matters. It is exactly what somebody who cannot sign with the old key would produce. Both kinds now name themselves, and the unproven one carries a warning that says what to do about it: > A device key was replaced on 29 Aug 2026, 12:00. The key it replaced did not sign for it. A replacement made by the person you are talking to normally does, so compare your safety number before you trust this one. The warning is a separate sentence after the date, so the clause naming the day stays intact and the existing exact-string tests are untouched. **On the tests.** One is a control: a test that only checked the unproven wording would pass if `rotate` were given the identical warning, which would be its own bug, so the two are asserted to differ. The Android side additionally pins its sentence against the iOS text, because two apps quietly drifting apart on a security warning is the failure this check exists to prevent. Found by tracing row 5 of the audit readiness sweep. Same class as §19.3, §6.26, §6.23/§6.24 and §6.27: built on one side, unwired on the other, with a comment asserting a property nothing delivered. Generated with Claude Code.
paulhitt (Migrated from gitlab.com) merged commit a4feabd129 into main 2026-09-22 19:20:50 +00:00
paulhitt commented 2026-09-22 19:20:51 +00:00 (Migrated from gitlab.com)

mentioned in commit a4feabd129

mentioned in commit a4feabd12997515867a20b4198a8300fb2060906
Sign in to join this conversation.