mirror of
https://github.com/fenleon/open-madrid.git
synced 2026-10-22 16:12:35 +00:00
registration: the prefpane presents the LOGIN RUN's anisette set (session-wide reuse, wire-pinned)
The trapped-binary decode (2026-10-15) shows ONE anisette mint serves the whole session — GSA hops, 2FA validate, postdata, both prefpane POSTs — so the PET is paired with the OTP window it was issued under. The rev-25/26 'fresh set at the sign-in POST' reading is corrected (confounded with the replay-guard era). GsaLoginChain mints one cpd per login run and exposes it as lastLoginAnisette (Client-Time frozen at the mint); GsaDelegateLoginClient's prefpane branch reuses a supplied Client-Time instead of re-minting. VEN step-2 wire fact recorded in spec rev 46: zero anisette on initializeValidation, no step-2 binding. Also wire-proven live: the GSA init 'ps' field is REQUIRED (omission answers ec=-80001).
This commit is contained in:
1 parent
9da53e31f8
commit
2ff994751c
5 files changed
+43
-14
No files matched your search
@@ -334,6 +334,7 @@ Ordered by value. IDs match the inline `TODO(capture):` markers above.
|
||||
- Rev 37 (2026-10-12, live-provisioning wire facts + the step-2 EM A/B): driving the Kotlin `ClearAnisetteProvider` against Apple's live endpoints for the first time (the session-26 EM A/B, NAC-NOTES session-26 addendum) surfaced two wire facts the offline scripted-HTTP tests could not catch: (1) the GSA lookup GET **404s without `X-Mme-Client-Info`**, and accepts only the angle-bracket form `<Model> <macOS;ver;build> <com.apple.AuthKit/1 (…)>` — a bare `com.apple.AuthKit/1 (com.apple.akd/1.0)` value 404s (the app's real value: `<MacBookPro18,3> <macOS;26.6.2;25G83> <com.apple.AuthKit/1 (com.apple.MobileSMS/1262.500.151.1.2)>`; imessage's `loginInfoFor`/`DEFAULT_LOGIN_INFO` already use the angle form); (2) the start/finish provisioning POST body keys are **case-sensitive**: `{header, request}` (lowercase — what the Kotlin sent) gets a **silent HTTP 200 with an EMPTY body**, `{Header, Request}` (as §1.5/C6 records) gets the real `Response.spim`/`ptm`/`tk` — fixed in `ClearAnisetteProvider` (Kotlin now sends the capitalized keys; 217 registration tests green; first live Kotlin provisioning run succeeded: metadata 400 B / mid 60 B). The vendored anisette client's fixed companion headers (rev-14 set) were confirmed against a live 2026-10-03 capture of the app's own lookup. Step-2 gate A/B (all via the identical transport): the app's genuine 10-08 blob replay → 5003/EM; our minted blob → 5003/EM; a FRESH blob minted by the app's own unmodified `ValidationCtx::new` the same hour (replay-state eliminated) → 5003/EM; with the full anisette header set on step 2 (± hardware headers, both blobs) → 5003/EM ×4 — **the anisette-on-step-2 hypothesis is falsified**. Residue: transport fingerprinting vs a server-side gate for everyone; the app's own-flow verdict is blocked on interactive IDS re-registration (user Apple-ID login) — removing `anisette_test/state.plist` re-fires provisioning but never the mint (no `ValidationCtx::new` hit in a fully-trapped run), and the vendored anisette client no longer traverses an intercepting proxy (baked DER root, SSL_CERT_FILE ignored).
|
||||
- Rev 38 (2026-10-12 late, the §1.1 step-2 5003/EM gate CLOSED — it is a TLS-stack fingerprint, not a blob/server-gate problem): after the user's 2FA re-login re-fired the app's own IDS registration and the full mint chain was observed ACCEPTED live (`vctx_new → step2_serialize → key_establishment → vctx_sign` ×3, gdb traps), fresh genuine blobs minted per-test (gdb `ValidationCtx::new`) settled the transport matrix: reqwest 0.11 + rustls 0.21 (+ the vendored client's baked Apple root DER, extracted from the .so at 0x24afa9 — webpki- roots/Mozilla does not include this Apple private root) POSTing the identical XML-plist envelope gets a real `session-info` response; curl (OpenSSL 3) over BOTH HTTP/2 and HTTP/1.1, and curl with UA/Accept headers removed (Accept-Language only), gets 5003/EM on the same fresh blobs. HTTP version and request headers are irrelevant: the VEN endpoint (Akamai-fronted identity.ess.apple.com) fingerprints the TLS ClientHello and rejects OpenSSL-shaped handshakes with the app-layer error 5003/EM. Earlier probes (JDK HttpURLConnection, python urllib, both cert-verif-off) were rejected for the same reason. Kotlin `NacRequestBlob` and the §1.1 framing are fully vindicated — the blob and envelope were never wrong. Consequence: the imessage tool's §1.1 HTTP must present a rustls-shaped handshake — JVM/Android default stacks (conscrypt/BoringSSL, OpenSSL-shaped) are expected to be rejected (unverified on-device); Conscrypt (Android's default stack, BoringSSL) is ALSO rejected — verified with a plain `HttpsURLConnection` probe on the lightos AVD posting a fresh genuine blob (EM-REJECTED) — so the accepted shape so far is rustls specifically, and the platform TLS stacks cannot do §1.1 step 2 at all. Implementation: a rust helper (rustls) behind UniFFI in `:server` (the calls/ pattern); a fingerprint-shaped JVM stack is not viable given the BoringSSL result. Evidence + probe sources: `registration/dev/clearadi/captures/c56j/tls-ab/` (NAC-NOTES session-26 EM-gate closure).
|
||||
- Rev 35 (2026-10-12, C56-a CLOSED — direct in-process replay of ValidationCtx::new, two byte-verified runs): the request blob's full recipe — header ‖ OAEP(pubkey, pearKey16 ‖ hmacKey20) ‖ RNG16 ‖ u32be(32) ‖ field32 ‖ HMAC-SHA1(hmacKey20, field32), with field32 = mapA[encrypt_cbc(mapB[02 ‖ u32be(1) ‖ innerKey16 ‖ zeros], iv, init_key(pearKey16))] and mapA/mapB the 0x2249f9/0x224af9 byte-substitution tables (table[byte], not xor). Kotlin `NacRequestBlob`; imessage unstubbed at C56-a; live-mint gate = C56-c only.
|
||||
- Rev 46 (2026-10-15, the trapped login decoded offline — the anisette is SESSION-WIDE, one mint; the prefpane "fresh anisette" reading corrected; VEN step-2 is anisette-free): full decode of the trapped 2FA login (`captures/c56k/ob-trap-20261014-201103/`, rustls + static-OpenSSL frames, HPACK-decoded): (1) **ONE anisette set serves the ENTIRE session** — one `X-Apple-I-MD` OTP, one `X-Apple-I-MD-M`, one `X-Apple-I-Client-Time` frozen at the session's mint (never refreshed) — byte-identical (hash-compared) across GsService2 init/complete, circle, 2FA validate, postdata ×5, CloudKit/escrowproxy, and BOTH prefpane `loginDelegates` POSTs. The rev-25/26 "OTP spent per request / the sign-in POST needs a fresh set" reading is CORRECTED: those observations predate the loginDelegates endpoint fix (session 29) and are confounded with the stamp replay-guard refusals of that era. The accepted prefpane POST pairs the PET with the OTP window it was issued under — the anisette↔login-session binding. (2) **The VEN step-2 (`TDIdentityService.woa/wa/initializeValidation`, 4 occurrences) carries ZERO anisette** — 8 headers only (h2 pseudo + accept/accept-language/accept-encoding/content-length), no OTP/MID/Client-Time/UA — no step-2 binding exists and our header-less step-2 is at parity; body = single `session-info-request` key, the 338-B blob with the constant `01 08 4b 2c 91 48 1d 9b 7d a0` header (`NacRequestBlob` exact). No separate keyEstablishment request exists on the wire. (3) A fresh stamp per delegate POST (2 POSTs → 2 distinct stamps; 692 B base64 = the 517-B stamp encoded). Code: `GsaLoginChain` now mints ONE cpd per login run (the cpd dict, the POST headers, and the exposed `lastLoginAnisette` — Client-Time included — share it) and `GsaDelegateLoginClient`'s prefpane branch reuses a supplied Client-Time instead of re-minting; imessage `register()` presents the login run's set at the prefpane. The 2FA-validate and postdata paths keep their fresh-per-call mints for now (the live 434 wall of rev 26 contradicts the wire's reuse — untangle only if the prefpane fix leaves residue); registration tests green.
|
||||
- Rev 45 (2026-10-13, the vendored delegate sign-in request RE'd to FULL parity — the prefpane endpoint speaks a V1 protocol, and the 400 ICLOUD_INVALID_DEVICE_TOKEN survives both body shapes): rustpush is now PUBLIC (OpenBubbles/rustpush, 2026-10-12) and the vendored .so embeds it with symbols — `login_apple_delegates` disassembled (closure 0xc3a5d0): fresh `os_config.generate_validation_data()` per sign-in (the public byte-exact VEN chain), the account's ClearADI anisette (persisted provisioning, OTP per call), the recorded header family (UA com.apple.iCloudHelper/282, X-Mme-Client-Info, X-Mme-Nas-Qualify, X-Apple-ADSID), Basic `username:PET`, optional `Cookie: termsAccepted=true` (terms flow only) — **and the body is the V1 kebab-case `AuthRequest {apple-id, client-id (plain v4, no uppercase), delegates, password = PET}` at `/setup/prefpane/login`** (`MacOSConfig::get_login_url` returns prefpane in the vendored build; the .so carries ZERO V2AuthRequest/protocolVersion/userInfo strings — the V1 shape public rustpush has commented out is what ships; the V2 wrapper stays recorded for `/setup/signin/v2/login`). Ladder (all on-device, same account, real C58): prefpane + V1 body WITHOUT Basic → 401 UNAUTHORIZED (the server reads Basic even on the V1 shape); prefpane + V1 + Basic + fresh PET → 400 ICLOUD_INVALID_DEVICE_TOKEN — the SAME verdict as V2 + Basic + fresh PET, so the body shape is not the variable and the request is at parity. User intel: the C58 Mac may have been REMOVED from the account — the 400 reads as Apple failing to tie the validation stamp's machine identity to a device record the account still has (the vendored client's last success 2026-10-10 predates any removal); next attempt is gated on confirming/re-verifying the Mac (or a fresh C58 from a currently-registered Mac). Code: `GsaDelegateLoginClient` V1 branch on PREFPANE_ENDPOINT; logs `captures/c56k/register-ladder-log-2026-10-13b.txt`.
|
||||
- Rev 44 (2026-10-13 later, the albert GENERIC_ERROR root-caused — it was OURS, not Apple's: **the public-repo port shipped a PLACEHOLDER FairPlay identity**): the staged `leaf.crt`/`identity.key` are self-signed (`CN = open-madrid-placeholder`, valid to 2036) — Apple bytes cannot ship in the public repo, and the port never wired the real pair. Apple's verdict for it is `SIGNATURE_VERIFICATION_FAILED` (not GENERIC_ERROR — that earlier page was the string-form `ActivationInfoXML`; with the rev-43 shapes the error is specific). The real identity (the one accepted live 2026-10-03) verifies fine: **host A/B with the genuine pair → device certificate on the FIRST probe, anisette/hardware headers unnecessary** (UA-only accepted too). Changes: `BundledFairPlaySigner` accepts an out-of-repo identity override (DER leaf + PKCS#1 PEM; null = committed placeholder — shape tests stay green); the imessage tool loads `/data/local/tmp/imessage-fairplay/{leaf.crt,identity.key}` (adb push, world-readable, no Apple bytes in any repo) and logs which identity is in use; the real pair lives in the gitignored captures (`captures/fairplay-identity/`). **On-device: activation ACCEPTED, courier connected, delegate sign-in reached the session-15 final wall `409 ICLOUD_UNSUPPORTED_DEVICE`** ("Cannot create another iCloud account with this device") — the recorded Nas-Qualify device-flag hypothesis (session 15) is now the only remaining §1.2 residue. Logs: `captures/c56k/register-final-log-2026-10-13.txt` + the anisette A/B (`AlbertAnisetteAbTest.kt`, also disproving the anisette-gate hypothesis).
|
||||
- Rev 43 (2026-10-13, REGISTER step-2 ACCEPTED on-device; the chain then moved to §1.2 and stalled at a NEW albert refusal): the rev-42 fix held live — the tool's step-2 POST returned a real `session-info` on the lightos AVD (validation → `initializing the validation session`, no 5080). Two follow-on fixes, then a new residue. (1) **Transport trust**: the engine SSLContext trusted ONLY the embedded Apple roots, but albert.apple.com chains to **DigiCert Global Root G2** (complete 3-cert chain on the wire) — `AppleTrust.platformTrustManager()` = system store + the Apple roots merged; the imessage engine context uses it (GSA's rev-40 pool + the public-CA endpoints in one manager). (2) **Albert request-shape regression**: the 7f960db port dropped two accepted shapes that session 15 carried — `ActivationInfoXML` must ride plist **`<data>` (bytes)**, not a string (the string form draws the `<Document>` GENERIC_ERROR page — pinned live 2026-10-02, re-confirmed 2026-10-13 by a host A/B), and the post carries **`User-Agent: ApplePushService/4.0 com.apple.iCloudHelper/282`** (rustpush `get_normal_ua("ApplePushService/4.0")`); both restored + shape tests updated. (3) **OPEN residue — albert GENERIC_ERROR**: with the restored shapes the activation is STILL refused with the generic wrapped-UI page (`ALEndPointErrorPage.genericError`, "Device activation failed. Please contact support.") for BOTH the user's real C58 identifiers and a synthetic identity (host A/B, same transport) — the shape now matches the session-15 accepted construction, so the refusal is server-side: top hypothesis is enforcement of the legacy FairPlay identity's leaf expiry (valid to 2024-10-11; activations stopped being observable after 2026-10-03), alternative is a new serial/record check. Next session: characterize against a CURRENT genuine activation (the vendored client's re-activation under gdb is user-gated) or a fresh FairPlay identity. Registration log excerpts archived (gitignored) in `captures/c56k/`; the A/B probe source archived beside it (`AlbertAbTest.kt`).
|
||||
|
||||
Reference in new issue
Block a user