mirror of
https://github.com/fenleon/open-madrid.git
synced 2026-10-22 16:12:35 +00:00
spec: rev 52-53 — the honest 6004 read narrows to the mint's inputs; the genuine-stamp A/B answers status 0 and the prefpane 400 was a stamp verdict
This commit is contained in:
1 parent
28e0432f09
commit
445c2fd642
1 file changed
+2
@@ -566,6 +566,8 @@ Each item names its arbitration path. Closed residue is noted inline.
|
||||
|
||||
## Revision history
|
||||
|
||||
- **Rev 53 (2026-10-16 late, session 40): the genuine-blob A/B convicts the mint's INPUTS — and the prefpane wall falls with it.** A freshly-minted GENUINE 517-B `validation-data` rode our register: the reference was force-re-registered (the id.plist recipe), its id-register body re-trapped (`captures/c56k/ob-trap-20261016-230027`; frame-015 = 2972 B gzip, sha256 `89ba2598…dffcc` → 13301 B XML, sha256 `7925f9fe…e6dd9`; `validation-data` = 517 B `02 d46edc11…`, sha256 `fa9dc9cf…8211a`), pushed via `/data/local/tmp/debug-stamp.b64` (the supplied-stamp hook now gates the pre-registration mint too — that block's §1.4 is the only register that runs), and REGISTER fired 3 m 49 s after the reference's mint. **Status 0 — every service accepted, twice.** The pre-registration register (imported IDS auth user, stored delegate pair) answered `status=0` on all four services (multiplex1/facetime.multi/ess logged; madrid accepted — `registered [email protected] (2 handle)`, `pre-registration: ok`), and the main flow then **passed §1.5's prefpane `loginDelegates` for the first time** (`gsa: iCloud sign-in` → no 400), ran §1.2 authenticate for a fresh cert, and registered again, all `status=0`. The tool's UI reads **Active** with both handles (`mailto:[email protected]`, `tel:+61420460590`), next renewal Mon 9:57 PM. Three protocol facts land. **(1) The prefpane 400 `ICLOUD_INVALID_DEVICE_TOKEN` IS a stamp verdict** — session 38's "stamp-independent" conclusion is inverted: its A/B lacked the genuine arm (garbage ≈ our mint — both invalid, hence the byte-identical 400), while the genuine stamp rides `X-Mme-Nas-Qualify` to a 200 with everything else unchanged (identity/anisette state byte-identical; the device record was 3 m 49 s old, and session 38 already measured record freshness as a no-op). **(2) The stamp is a self-contained ~15-min credential, not bound to the presenting connection's VEN session** — minted inside the reference's NAC session on the host, accepted ~4 min later through our register, which (supplied-stamp path) makes zero VEN calls of its own. **(3) Nothing downstream of the mint is left** — body, headers, auth credentials and both §1.2 routes are correct end-to-end. **The mint ALGORITHM was already exonerated (rev 47: byte-exact from recovered inputs); what fails is the INPUTS — the NAC key-establishment session material our ClearADI port feeds it.** That is the surviving defect and the next work; the reference's live §1.1 exchange for the diff is captured whole in `ob-trap-20261016-230027` (frames 001–014: the pre-register VEN/absinthe exchange, 012/017/020 = parsed responses; 015 = the register body). Caveat: the AVD's Active registration rides a BORROWED stamp — any re-register/renewal with our own mint will answer 6004 until the inputs are fixed.
|
||||
- **Rev 52 (2026-10-16, session 39): the §1.4 register was finally read honestly — it answers `6004` with `services: []` — and the request's remaining suspects are measured down to one.** Three findings, all measured. **(1) The credential that unblocks §1.2 is the persisted IDS auth user, not the delegate token.** The reference keeps its `IDSUser` in `~/.local/share/bluebubbles/id.plist[0]` (`user_id = D:<dsid>`, `user_type = Apple`, `protocol_version = 1640`, `auth_keypair = {cert: 2092 B DER X.509, private: 1190 B PKCS#1 RSA}`); rustpush re-registers from that record and never replays a delegate token (`auth.rs:327` only *creates* the record from an `IDSDelegateResponse`). Ours was never persisted — `/data/local/tmp`'s state file carries `users: []` plus a 12-h-old `delegateAuthToken`, which is why §1.2 has answered 6008 since session 34. Importing the reference's pair (PKCS#8 key + DER cert at `/data/local/tmp/debug-auth-{key,cert}.der`, an A/B hook in `idsRegister` that skips §1.2) reaches the register: `authenticate: SKIPPED — imported IDS auth user (cert 2092 B)` → `pre-registration: register: no madrid service (status=6004, services=[])`. **(2) The shape-only fixture never pinned *values*, and four were wrong.** Re-reading the captured oracle body (`captures/c56k/ob-trap-20261014-201103/frame-026.bin`) gives the recorded values: `device-name = Mac-<platform serial>`, `os-version = macOS,<product version>,<build>`, `software-version = <build>`, `private-device-data.pn = macOS` (the literal platform name, **not** the product type), `.pv = <product version>`, `.d = <Apple-epoch seconds>` with 6 decimals, `user-id` = `D:<dsid>` on every service `[RP:macos.rs:77,89,157, ids/user.rs:982+]`, and `x-auth-user-id-<N>` = that same string. Our builder sent `device-name = "Light Phone III"`, `os-version = <product version>`, `software-version = "1.0"`, `pn = <product type>`; fixed, re-run → **still 6004, so none of the four is the cause**. **(3) `x-auth-user-id-0` is exonerated**: our device state carries `delegateProfileId = D:18580270837` — byte-identical to the oracle's `user-id`, so suspect #2 of the handover is closed. The stamp is next in line but its *shape* is parity: the genuine 517-B `validation-data` is `02 | rand16 | sig16 | u32be(480) | blob480` with `blob480 = 05 | u32be(1) | u32be(0x180) | scrambled384 | u64be(0x4f) | cert79`, byte-identical in layout to `NacValidation.mint`. **6004's `message` is decoded further**: `SED:3:VEN-PROD:<uuid>:<uuid>:<epoch-seconds>:<uuid>:<sha256>:EM`, and that epoch is the second of *this very request* (6004 at 22:39:36 → `1792183176`; a second attempt 3 s later → `1792183179` with a wholly new uuid/hash set), i.e. the server returns a **fresh** VEN session per attempt rather than echoing ours — and the hash is not sha256 over the push token, the user id, the serial, the platform UUID or the auth certificate (server-side, as rev 48 found). Two more negatives: re-minting and immediately retrying answers 6004 again, so this is not staleness or request spacing; and `postdata` liveness succeeds (its `gsa: postdata failed:` line is absent), so the device-record hop is not failing silently. **The one surviving suspect is the content of the mint's inputs** — the NAC/key-establishment session material behind the 517-B stamp — and it is decidable without new code: `/data/local/tmp/debug-stamp.b64` already replaces the mint with a supplied blob, so a freshly-minted genuine blob (re-trap the reference's register write) tests it directly. Ops note for that run: the register reaches Apple ~2 s after the mint, and the tool's UI needs two taps at `540,1172` (REGISTER → export-code screen → REGISTER).
|
||||
- **Rev 51 (2026-10-16, session 37):** the §1.4 **request body is now capture-exact** — the two remaining divergences from the only working oracle are closed on paper and in code. (1) **Four services, not one:** the reference registers `[madrid, multiplex1, facetime.multi, ess]` in that order, each row a constant from its own source (`api.rs:580` + the four `IDSService` constants), with per-service capabilities/sub-services/`client-data` and a per-service `ec-version` that is a real `1.0` on madrid and the integer `1` elsewhere [CAP-REG42]. Our register sent madrid alone. Ported as `RegisterServiceCatalog` (four rows; one NGM identity and one auth certificate shared by all four, as the capture shows). (2) **The `uris` are server-fetched, not derived:** the reference calls `id-get-handles` per user before building the body and puts the returned list on every service [RP:ids/user.rs:791,987], [CAP-REG42] — our register invented one handle from the login username. Ported as `IdsHandleFetcher` (bodiless signed GET, unindexed `x-auth-user-id`); the login-derived handle survives only as a loud fallback. Also recorded: the register sets `accept-encoding: gzip` alongside `content-encoding: gzip` [CAP-REG42] (C3's last open half). Structural parity is pinned by `RegisterServiceCatalogTest` against a shape-only fixture extracted from the captured body (`registration/src/test/resources/imessage/register-reference-shape.plist`, source sha256 in the fixture; the reference user's identifying values are not recorded). Nothing here is verified against Apple yet — the 6004 read is still pending.
|
||||
- **Rev 50 (2026-10-16, session 36):** reference survey closed — a negative result, recorded so it is not re-run. **No implementation available on this machine can confirm a registration**, so the reference's captured bytes are the only oracle. `open-absinthe` is the official **stub** (every body `todo!()`; "closed source ... no actual functionality"), so it cross-checks nothing — the [OA] legend entry is load-bearing rather than merely descriptive. `imessagego` (snapshot 2024-01-16) **requires an external Mac / jailbroken-iPhone registration provider plus a relay** and never registers standalone, so it evidences request *shape* only. Its back half matches ours: identical `authenticateDS` body shape (`{authentication-data.auth-token, csr, realm-user-id}`), the same eight register keys, **one service `com.apple.madrid`**, and its own degenerate deregister (`DeRegisterIDS` — register with nil handles/cert pairs) confirming independently that the empty-services body is a deregister, not a register step. Its front half is a different Apple-ID world: **no anisette** (zero `X-Apple-I-MD` hits), no `GsService2`, no `spd`/PET, no delegate — login is a single call to `profile.ess.apple.com/…/authenticateUser` (plist `{username, password}`, 2FA code appended to the password), and validation data comes from an external NAC server. Consequence for our 6004: anisette cannot be its cause. Also recorded: the shipped reference binary is **ClearADI-built** (1026 `clearadi` / 0 `RemoteAnisetteProviderV3` / 78 `open_absinthe` symbol hits), so a checkout whose `Cargo.toml` enables `remote-anisette-v3` is not the shipped build — trust the binary.
|
||||
- **Rev 49 (2026-10-16 late evening):** rev 48's "register #2" is NOT a register — an empty-services body with no `x-auth-*` headers is the client's DEREGISTER. rustpush emits an empty-services register in exactly one place: `register(config, aps, &[], &mut [], identity)` inside `reset_state(state, reset_hw, logout)` (`/tmp/openbubbles/rust/src/api/api.rs:2424`, "try deregistering from iMessage, but if it fails we don't really care"), reached from `rustpush_service.dart:348 markFailedToLogin()` → `:4621 Future reset()` → `api.resetState`; both healthy register paths (`api.rs:580 register_ids`, `identity_manager.rs:344`) always send the four services. A captured FULL→EMPTY pair therefore means *register succeeded, a later step failed, the app reset*. The step is removed from `idsRegister`. Also settled by measurement rather than by response capture: **the reference's own register returns status 0** — forcing a re-register (host-side id.plist edit: `registered_at_s = now − 7200` **plus** `heartbeat_interval_s = 600`, a key the app deletes on write) rotates every service `id_keypair` certificate to `notAfter = register_time + 45 d` and renews the `env_hash`/pseudonym set, which `register()` can only do after a zero status (it returns `Err` before recording on any non-zero status). A register carries no anisette headers — `SignedRequest::sign` (`rustpush/src/auth.rs:395+`) appends only `x-{auth|push|id}-nonce|sig|cert[-i]` — so the absinthe context of a register is exactly its `validation-data`. Capture limits worth recording: the register rides HTTP/2 (PRI preface + HPACK), so its *headers* are not recoverable from a plaintext write trap, and its `plist::from_bytes::<Value>` response parse is LTO-inlined into `register`, so no breakpoint fires for the *response* body (needs a rustls read-path hook, e.g. `ConnectionCore::process_new_packets`). Reference body shape re-verified from frame-016: four services (`com.apple.madrid` 17 flags/"Messenger" + sub-services sms/gelato/biz/gamecenter.imessage, `com.apple.private.alloy.multiplex1` 1/"com.apple.private.alloy", `com.apple.private.alloy.facetime.multi` 1/"Invitation", `com.apple.ess` 1/"Invitation"), one user each, `uris` = tel + mailto on every service, `client-data` 52/11/13/9 keys, the 14 `private-device-data` keys, 517 B stamp. Our register still sends madrid only, with one handle.
|
||||
|
||||
Reference in new issue
Block a user