Skip to content

Verify signature against cached public key after signing #2571

@fnando

Description

@fnando

Suggested by @mootz12 on #2569 (comment) — tracked as a follow-up so it can land as a single, generalized change.

Context

Both LedgerEntry (added in #2569) and SecureStoreEntry carry a cached/derived public key alongside the underlying signing primitive. *Entry::sign_tx_hash derives the SignatureHint from that cached key and then signs with the live device/keychain. If the cached key ever drifts from what the underlying signer actually produces (corrupted TOML, wrong device plugged in, alias points at a different hd-path than expected, schema migration glitch), the resulting transaction has a hint that disagrees with its signature — Horizon rejects it later with an opaque error rather than failing locally with a clear message.

The same drift class applies to the Soroban auth-entry path (*Entry::sign_payload), where signer::sign_soroban_authorization_entry embeds signer.get_public_key() (the cached value) next to the device-produced signature in the auth signature ScVal map.

Proposal

Add a post-sign ed25519 verification step in the Ledger / SecureStore signing paths that verifies the produced signature against the cached public key and errors with a clear message on mismatch. Should cover:

  • LedgerEntry::sign_tx_hash
  • LedgerEntry::sign_payload
  • SecureStoreEntry::sign_tx_hash
  • SecureStoreEntry::sign_payload

Gated on self.public_key.is_some() so the --sign-with-ledger cacheless flow (which fetches the pubkey live and has nothing to drift from) is unaffected. ed25519 verification is microseconds — cost is negligible.

Out of scope

SignerKind::Local and SignerKind::Lab, where the public key is derived from the same in-process primitive that signs and drift is not possible.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Backlog (Not Ready)

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions