Skip to content

fix: move peer key validation into IKeyManager interface (WAPI-1116)#70

Open
chakra-guy wants to merge 9 commits intomainfrom
cyfrin/wapi-1116
Open

fix: move peer key validation into IKeyManager interface (WAPI-1116)#70
chakra-guy wants to merge 9 commits intomainfrom
cyfrin/wapi-1116

Conversation

@chakra-guy
Copy link
Collaborator

@chakra-guy chakra-guy commented Feb 25, 2026

Summary

Adds peer public key validation at handshake and session resume time by introducing a validatePeerKey(key: Uint8Array): void method on the IKeyManager interface. This keeps the core package crypto-agnostic while letting each implementation validate keys according to its own crypto system.

  • IKeyManager gains validatePeerKey() - validates peer keys at ingestion time
  • Wallet client validates in _createSession(), dapp client validates in both connection handlers
  • BaseClient.resume() validates persisted peer keys before reconnecting
  • IConnectionHandlerContext (dapp-client) now exposes keymanager for handler-level validation
  • NaN guard on session expiry timestamps (both set and get)
  • New INVALID_KEY error code in ErrorCode enum
  • Reference implementation uses eciesjs.PublicKey.fromHex() for full curve-point validation (no new dependencies)

Breaking changes

  • IKeyManager has a new required method: validatePeerKey(key: Uint8Array): void

Jira

Test plan

  • All unit tests pass (61/61)
  • Build passes for core, dapp-client, wallet-client
  • Lint passes (0 warnings)
  • Verified PublicKey.fromHex() rejects: wrong length, wrong prefix, not-on-curve, empty
  • Handler tests updated with mock keymanager

Note

Medium Risk
Introduces a breaking API change (IKeyManager.validatePeerKey) and enforces key validation during handshake/resume, which can surface new runtime failures if implementations are incomplete or overly strict. Session expiry parsing now treats non-numeric/NaN values as expired, potentially deleting previously-stored malformed sessions.

Overview
Adds peer public-key validation as a first-class requirement. IKeyManager now includes validatePeerKey(key), and dapp/wallet flows call it when ingesting peer keys (wallet session creation, dapp handshake offer handling, and BaseClient.resume() for persisted sessions), with demo/tests updated to implement the method (ECIES curve-point validation in real managers; no-op in load tests).

Hardens session persistence against invalid expiry timestamps. SessionStore now rejects saving sessions with NaN expiry and treats non-numeric/NaN expiresAt values as expired on read (auto-deleting them), with new tests covering these cases; wallet connect error handling also avoids leaving the client stuck in CONNECTING when session creation fails.

Written by Cursor Bugbot for commit 460249c. This will update automatically on new commits. Configure here.

Add validateSecp256k1PublicKey utility that checks for exactly 33 bytes
and a 0x02/0x03 prefix. Applied at all public key ingestion points:
wallet-client session creation, both dapp-client connection handlers,
and SessionStore deserialization.

Also guards against NaN in session expiry timestamps on both set and get.
Tests used Uint8Array(33) filled with zeros (0x00 prefix) which is now
rejected by the secp256k1 public key validation added in this PR.
Updated to use 0x02 prefix for a valid compressed key format.
If validateSecp256k1PublicKey threw on a malformed peer key, the
wallet client state would be stuck at CONNECTING with no cleanup,
permanently bricking the instance. Moving _createSession into the
try block ensures disconnect() runs on validation failure.
Copy link

@adonesky1 adonesky1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a comment/request

The previous approach leaked secp256k1-specific validation into the
core package, breaking its crypto-agnostic architecture. This moves
validation behind the IKeyManager interface so each implementation
validates keys according to its own crypto system.

- Add validatePeerKey() to IKeyManager interface
- Delete standalone validateSecp256k1PublicKey utility
- Remove validation from SessionStore.get() (validated at ingestion)
- Add validation in BaseClient.resume() for persisted sessions
- Wire keymanager into dapp-client handler context
- Use eciesjs PublicKey.fromHex() for curve-point validation
@chakra-guy chakra-guy changed the title fix: validate incoming public keys as compressed secp256k1 (WAPI-1116) fix: move peer key validation into IKeyManager interface (WAPI-1116) Feb 26, 2026
@chakra-guy chakra-guy requested a review from adonesky1 February 26, 2026 09:20
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

- Core changelog: categorize validatePeerKey as Changed (breaking
  interface addition), keep NaN guard under Fixed
- Dapp/wallet-client changelogs: recategorize peer key validation
  entries as Fixed
- Wallet-client: reset state to DISCONNECTED when _createSession
  throws before session is assigned, preventing permanent CONNECTING
  state
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants