diff --git a/docs/reverse-engineering/grpc-event-query-capture.md b/docs/reverse-engineering/grpc-event-query-capture.md index cb56466..a95e4a8 100644 --- a/docs/reverse-engineering/grpc-event-query-capture.md +++ b/docs/reverse-engineering/grpc-event-query-capture.md @@ -229,3 +229,28 @@ size) — using .NET `ECDiffieHellman`, establish the client key, then reissue t Open question for Path B: whether merely *completing* the ECDH key agreement registers the client key (so the zeroed openParameters token still rides through), or whether the token must also be derived from the shared secret (full KDF/cipher RE). + +### Path B started 2026-06-23 — ExchangeKey ECDH works; cleared 2 of 3 layers + +Implemented `HistoryService.ExchangeKey` as a **pure-managed P-256 ECDH** key exchange +(`HistorianNativeHandshake.BuildExchangeKeyClientHello` / `DeriveExchangeKeySecret`, .NET +`ECDiffieHellman` over `nistP256`; wire format `"ECK1" + u32(32) + X(32) + Y(32)`) and wired it into +`HistorianGrpcHandshake.OpenSession(eventConnection: true)` ahead of the v8 `OpenConnection`, +on the same context-key handle. Live result against the server: the **`ExchangeKey` RPC succeeds** +(the server accepted our public key), and the v8 `OpenConnection` error **moved one layer deeper**: + +``` +Path A (no ExchangeKey): 132/34 "Failed to get client key" +Path B (ExchangeKey ECDH): 132/171 AuthenticationFailed "EstablishConnection — Authentication failed" +``` + +So the ECDH cleared the client-key check; the remaining blocker is **authentication**: the 26-byte +v8 credential token must be a *valid* value derived from the ECDH shared secret (not zeros). This is +the token KDF/cipher — the part that is not yet reverse-engineered and that would require analyzing +AVEVA's native ExchangeKey/credential crypto to recover the derivation (the .NET-shipped result stays +pure managed either way). The "Path B-lite" hypothesis (zeroed token rides through after key +agreement) is therefore disproven at the auth layer — 2 of 3 layers are cleared, the 3rd is the +credential-token derivation. ExchangeKey + the v8 serializer are committed and ready; the orchestrator +stays on v6 (set `eventConnection: true` to re-arm once the token KDF lands). The token-loop routing +guardrail (`HistorianGrpcHandshakeRoutingTests`) was scoped to the closure so the legitimate +ExchangeKey call is allowed while still pinning that the Negotiate token loop never routes there.