Skip to content

Commit

Permalink
fix: signing with Ledger throws an empty error (#349)
Browse files Browse the repository at this point in the history
* fix: bump ledger-cosmos-go

* feat: update cosmos-sdk code for ledger-cosmos-go

Inspired by cosmos#14661
  • Loading branch information
rootulp authored Oct 12, 2023
1 parent c525ad7 commit c226e8b
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 63 deletions.
2 changes: 1 addition & 1 deletion crypto/keyring/keyring.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ func SignWithLedger(k *Record, msg []byte) (sig []byte, pub types.PubKey, err er
return
}

sig, err = priv.Sign(msg)
sig, err = priv.SignLedgerAminoJSON(msg)
if err != nil {
return nil, nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion crypto/ledger/ledger_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func (mock LedgerSECP256K1Mock) GetAddressPubKeySECP256K1(derivationPath []uint3
return pk, addr, err
}

func (mock LedgerSECP256K1Mock) SignSECP256K1(derivationPath []uint32, message []byte) ([]byte, error) {
func (mock LedgerSECP256K1Mock) SignSECP256K1(derivationPath []uint32, message []byte, p2 byte) ([]byte, error) {
path := hd.NewParams(derivationPath[0], derivationPath[1], derivationPath[2], derivationPath[3] != 0, derivationPath[4])
seed, err := bip39.NewSeedWithErrorChecking(testdata.TestMnemonic, "")
if err != nil {
Expand Down
30 changes: 24 additions & 6 deletions crypto/ledger/ledger_secp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ type (
// Returns a compressed pubkey and bech32 address (requires user confirmation)
GetAddressPubKeySECP256K1([]uint32, string) ([]byte, string, error)
// Signs a message (requires user confirmation)
SignSECP256K1([]uint32, []byte) ([]byte, error)
// The last byte denotes the SIGN_MODE to be used by Ledger: 0 for
// LEGACY_AMINO_JSON, 1 for TEXTUAL. It corresponds to the P2 value
// in https://github.com/cosmos/ledger-cosmos/blob/main/docs/APDUSPEC.md
SignSECP256K1([]uint32, []byte, byte) ([]byte, error)
}

// PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano we
Expand All @@ -51,7 +54,7 @@ type (
// This function is marked as unsafe as it will retrieve a pubkey without user verification.
// It can only be used to verify a pubkey but never to create new accounts/keys. In that case,
// please refer to NewPrivKeySecp256k1
func NewPrivKeySecp256k1Unsafe(path hd.BIP44Params) (types.LedgerPrivKey, error) {
func NewPrivKeySecp256k1Unsafe(path hd.BIP44Params) (types.LedgerPrivKeyAminoJSON, error) {
device, err := getDevice()
if err != nil {
return nil, err
Expand Down Expand Up @@ -88,15 +91,28 @@ func (pkl PrivKeyLedgerSecp256k1) PubKey() types.PubKey {
return pkl.CachedPubKey
}

// Sign returns a secp256k1 signature for the corresponding message
// Sign returns a secp256k1 signature for the corresponding message using
// SIGN_MODE_TEXTUAL.
func (pkl PrivKeyLedgerSecp256k1) Sign(message []byte) ([]byte, error) {
device, err := getDevice()
if err != nil {
return nil, err
}
defer warnIfErrors(device.Close)

return sign(device, pkl, message)
return sign(device, pkl, message, 1)
}

// SignLedgerAminoJSON returns a secp256k1 signature for the corresponding message using
// SIGN_MODE_LEGACY_AMINO_JSON.
func (pkl PrivKeyLedgerSecp256k1) SignLedgerAminoJSON(message []byte) ([]byte, error) {
device, err := getDevice()
if err != nil {
return nil, err
}
defer warnIfErrors(device.Close)

return sign(device, pkl, message, 0)
}

// ShowAddress triggers a ledger device to show the corresponding address.
Expand Down Expand Up @@ -228,13 +244,15 @@ func validateKey(device SECP256K1, pkl PrivKeyLedgerSecp256k1) error {
// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, returning
// an error, so this should only trigger if the private key is held in memory
// for a while before use.
func sign(device SECP256K1, pkl PrivKeyLedgerSecp256k1, msg []byte) ([]byte, error) {
//
// Last byte P2 is 0 for LEGACY_AMINO_JSON, and 1 for TEXTUAL.
func sign(device SECP256K1, pkl PrivKeyLedgerSecp256k1, msg []byte, p2 byte) ([]byte, error) {
err := validateKey(device, pkl)
if err != nil {
return nil, err
}

sig, err := device.SignSECP256K1(pkl.Path.DerivationPath(), msg)
sig, err := device.SignSECP256K1(pkl.Path.DerivationPath(), msg, p2)
if err != nil {
return nil, err
}
Expand Down
11 changes: 11 additions & 0 deletions crypto/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ type LedgerPrivKey interface {
Type() string
}

// LedgerPrivKeyAminoJSON is a Ledger PrivKey type that supports signing with
// SIGN_MODE_LEGACY_AMINO_JSON. It is added as a non-breaking change, instead of directly
// on the LedgerPrivKey interface (whose Sign method will sign with TEXTUAL),
// and will be deprecated/removed once LEGACY_AMINO_JSON is removed.
type LedgerPrivKeyAminoJSON interface {
LedgerPrivKey
// SignLedgerAminoJSON signs a messages on the Ledger device using
// SIGN_MODE_LEGACY_AMINO_JSON.
SignLedgerAminoJSON(msg []byte) ([]byte, error)
}

// PrivKey defines a private key and extends proto.Message. For now, it extends
// LedgerPrivKey (see godoc for LedgerPrivKey). Ultimately, we should remove
// LedgerPrivKey and add its methods here directly.
Expand Down
40 changes: 22 additions & 18 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ require (
github.com/cosmos/cosmos-sdk/db v1.0.0-beta.1
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/iavl v0.19.6
github.com/cosmos/ledger-cosmos-go v0.12.2
github.com/cosmos/ledger-cosmos-go v0.13.1
github.com/gogo/gateway v1.1.0
github.com/gogo/protobuf v1.3.2
github.com/golang/mock v1.6.0
Expand Down Expand Up @@ -51,21 +51,21 @@ require (
github.com/tendermint/tendermint v0.34.28
github.com/tendermint/tm-db v0.6.7
github.com/tidwall/btree v1.5.0
golang.org/x/crypto v0.7.0
golang.org/x/crypto v0.14.0
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4
google.golang.org/grpc v1.55.0
google.golang.org/protobuf v1.30.0
google.golang.org/genproto/googleapis/api v0.0.0-20230920204549-e6e6cdab5c13
google.golang.org/grpc v1.58.3
google.golang.org/protobuf v1.31.0
pgregory.net/rapid v0.4.7
sigs.k8s.io/yaml v1.3.0
)

require (
cloud.google.com/go v0.110.0 // indirect
cloud.google.com/go/compute v1.18.0 // indirect
cloud.google.com/go v0.110.8 // indirect
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v0.12.0 // indirect
cloud.google.com/go/storage v1.28.1 // indirect
cloud.google.com/go/iam v1.1.2 // indirect
cloud.google.com/go/storage v1.30.1 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect
Expand Down Expand Up @@ -104,8 +104,9 @@ require (
github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.7.0 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.4 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
Expand Down Expand Up @@ -152,21 +153,24 @@ require (
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/ulikunitz/xz v0.5.8 // indirect
github.com/zondax/hid v0.9.1 // indirect
github.com/zondax/ledger-go v0.14.1 // indirect
github.com/zondax/ledger-go v0.14.2 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.15.1 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.15.1 // indirect
go.opentelemetry.io/otel/sdk v1.15.1 // indirect
go.opentelemetry.io/otel/trace v1.15.1 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/oauth2 v0.6.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.110.0 // indirect
google.golang.org/api v0.128.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20231002182017-d307bd883b97 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
Loading

0 comments on commit c226e8b

Please sign in to comment.