docs(grpc-events): Path B — ExchangeKey ECDH clears 2 of 3 layers

Records that the pure-managed P-256 ExchangeKey works (cleared the v8 client-key
check; error advanced to 132/171 AuthenticationFailed). The remaining layer is the
26-byte credential-token KDF, which requires recovering the native key derivation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
This commit is contained in:
Joseph Doherty
2026-06-23 10:31:37 -04:00
parent d67f6f5e96
commit 3fd522fa10
@@ -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.