Skip to content

fix(types): bind derivation_path in SignTxMessage.Raw() (#162)#163

Merged
anhthii merged 1 commit into
fystack:masterfrom
DNK90:fix/issue-162-bind-derivation-path
Jul 3, 2026
Merged

fix(types): bind derivation_path in SignTxMessage.Raw() (#162)#163
anhthii merged 1 commit into
fystack:masterfrom
DNK90:fix/issue-162-bind-derivation-path

Conversation

@DNK90

@DNK90 DNK90 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the signature-binding gap reported in #162.

SignTxMessage.Raw() builds the canonical payload that the event initiator signs and that nodes re-compute during verification. It previously omitted derivation_path, even though nodes use that field to select the child key for signing (CKD.Derive). An attacker able to tamper messages on the bus could change derivation_path without invalidating the initiator signature, making a node sign the authenticated tx digest with a different derived key than intended. Because ComposeAuthorizerRaw() wraps Raw(), authorizer signatures were affected as well.

Change

  • Include DerivationPath in the signed payload of SignTxMessage.Raw().
  • ComposeAuthorizerRaw() now covers it automatically (it wraps Raw()).

Backward compatibility

Uses json:"derivation_path,omitempty". Messages with an empty derivation_path serialize byte-for-byte as before, so existing signed traffic (initiators that don't use HD derivation) keeps verifying — no lockstep upgrade required for the empty-path case.

Tests

  • pkg/types: backward-compat bytes (empty path == old output), path inclusion, path changes Raw(), and the signature-binding property (tampering the path breaks ed25519.Verify).
  • pkg/identity: VerifyInitiatorMessage end-to-end — a tampered derivation_path is rejected through the production verify path.

go test ./pkg/types/... ./pkg/identity/... passes; gofmt/go build ./... clean.

Note for downstream initiators

Initiators that build & sign SignTxMessage (e.g. the coordinator/API) must use the same []uint32 derivation_path type and include it in their own Raw() once they start sending non-empty paths, to keep the canonical bytes identical on both sides.

Relates to #162

SignTxMessage.Raw() builds the canonical payload signed by the event
initiator and re-computed by nodes during verification. It previously
omitted derivation_path, even though nodes use that field to select the
child key for signing (CKD.Derive). An attacker able to tamper messages
on the bus could change derivation_path without invalidating the
initiator signature, making a node sign the authenticated tx digest with
a different derived key than intended.

Include DerivationPath in the signed payload so it is authenticated.
ComposeAuthorizerRaw wraps Raw(), so authorizer signatures now cover it
too.

Uses `omitempty` for backward compatibility: messages with an empty
derivation_path serialize byte-for-byte like before, so existing signed
traffic (e.g. clients that do not use HD derivation) keeps verifying.

Adds unit tests for: backward-compat bytes, path inclusion, and the
signature-binding property (tampering the path breaks verification),
plus a VerifyInitiatorMessage test through the production verify path.

Relates to fystack#162
@DNK90 DNK90 force-pushed the fix/issue-162-bind-derivation-path branch from f3b0488 to e99507a Compare July 3, 2026 05:10
@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@anhthii

anhthii commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

LGTM!

@anhthii anhthii merged commit 0a39b5e into fystack:master Jul 3, 2026
21 checks passed
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