diff --git a/handlers/auth_test.go b/handlers/auth_test.go index ae953fb..e3af8c0 100644 --- a/handlers/auth_test.go +++ b/handlers/auth_test.go @@ -4,6 +4,7 @@ import ( "crypto/ecdsa" "encoding/base64" "encoding/hex" + "fmt" "math" "testing" @@ -64,3 +65,50 @@ func TestSign(t *testing.T) { _, err = prepareBearerToken(bt, false, false) require.NoError(t, err) } + +func TestWalletConnect20Signature(t *testing.T) { + stV10 := &SessionToken{ + BearerToken: BearerToken{ + Token: "ChAMDRXN+epG44eLachkJJQKEhsKGTV0c7bhRT/GDdQsm7gPCNG63g4isq97/E8aBgixAhjNASIhAzFSJMOEdkH6YbJYhHN0w1wrgiz/QFPZvQ2D/8oqNrQjMgQIARAB", + Signature: "87f54d849fc887dfda7546b4edde6f83397cea798a0c5edf979149659007fbe868e7d8a3b6813c56a81c266a5d28956b28b59ba87cd6aff09d518bcfe11474276e5c3d4d714eb13d43601cae70aef11e", + Key: "027e9b7e3b9f07b6bcb59b050f11616c78f433806d4314f7c72e5ac1d9f4d1fb02", + }, + Verb: 1, + } + + stV20 := &SessionToken{ + BearerToken: BearerToken{ + Token: "ChBLgy6hRhBIpJVysyjM84OUEhsKGTV0c7bhRT/GDdQsm7gPCNG63g4isq97/E8aBgi0AhjQASIhAkwGSfK6lIf6HkuzG1YSSeFn5D/qIesknvBFTGN8qod5MgQIARAB", + Signature: "e286951bfd1cc172b70fcd6a832d2121a5a635493a5b15c385b8001e676576df308898615cc25efc7fd649a7b3052453338b96671776d498c15cf032fdb072ec30f30aba0bb9375c6575fac8a4d4a19d", + Key: "027e9b7e3b9f07b6bcb59b050f11616c78f433806d4314f7c72e5ac1d9f4d1fb02", + }, + Verb: 1, + } + + _, err1 := prepareSessionToken(stV10, true) + require.NoError(t, err1) + + err2 := prepareSessionToken2(stV20) + require.NoError(t, err2) + +} + +func prepareSessionToken2(st *SessionToken) error { + data := []byte(st.Token) + + signature, err := hex.DecodeString(st.Signature) + if err != nil { + return fmt.Errorf("couldn't decode signature: %w", err) + } + + ownerKey, err := keys.NewPublicKeyFromString(st.Key) + if err != nil { + return fmt.Errorf("couldn't fetch session token owner key: %w", err) + } + + if !Verify((*ecdsa.PublicKey)(ownerKey), data, signature) { + return fmt.Errorf("invalid signature") + } + + return nil +} diff --git a/handlers/wallet_connect.go b/handlers/wallet_connect.go new file mode 100644 index 0000000..16b82b4 --- /dev/null +++ b/handlers/wallet_connect.go @@ -0,0 +1,68 @@ +package handlers + +import ( + "crypto/ecdsa" + "crypto/elliptic" + + crypto "github.com/nspcc-dev/neofs-crypto" +) + +const ( + // saltSize is the salt size added to signed message. + saltSize = 16 + // signatureLen is the length of RFC6979 signature. + signatureLen = 64 +) + +// SignedMessage contains mirrors `SignedMessage` struct from the WalletConnect API. +// https://neon.coz.io/wksdk/core/modules.html#SignedMessage +type SignedMessage struct { + Data []byte + Message []byte + PublicKey []byte + Salt []byte +} + +// Verify verifies message using WalletConnect API. +func Verify(p *ecdsa.PublicKey, data, sign []byte) bool { + if len(sign) != signatureLen+saltSize { + return false + } + + //salt := sign[signatureLen:] + return VerifyMessage(p, SignedMessage{ + Data: sign[:signatureLen], + Message: data, + //Salt: salt, + }) +} + +// SignMessage signs message with a private key and returns structure similar to +// `signMessage` of the WalletConnect API. +// https://github.com/CityOfZion/wallet-connect-sdk/blob/eca3e5a4d9707c7a9c4d2828a7bf64222ce563ef/packages/wallet-connect-sdk-core/src/index.ts#L318 +// https://github.com/CityOfZion/neon-wallet/blob/a5a3ded5d2db80649a528a195a5914709df2d587/app/context/WalletConnect/helpers.js#L185 +func SignMessage(p *ecdsa.PrivateKey, msg []byte) (SignedMessage, error) { + // It seems we have to fix sing in neofs-crypto + // https://github.com/CityOfZion/neon-js/blob/f316675898117cddf03ea089e3177ef05877845f/packages/neon-core/src/wallet/signing.ts#L23 + // https://github.com/CityOfZion/neon-js/blob/f316675898117cddf03ea089e3177ef05877845f/packages/neon-core/src/u/basic/curve.ts#L32 + panic("not implemented") +} + +// VerifyMessage verifies message with a private key and returns structure similar to +// `verifyMessage` of WalletConnect API. +// https://github.com/CityOfZion/wallet-connect-sdk/blob/eca3e5a4d9707c7a9c4d2828a7bf64222ce563ef/packages/wallet-connect-sdk-core/src/index.ts#L345 +// https://github.com/CityOfZion/neon-wallet/blob/a5a3ded5d2db80649a528a195a5914709df2d587/app/context/WalletConnect/helpers.js#L197 +func VerifyMessage(p *ecdsa.PublicKey, m SignedMessage) bool { + if p == nil { + x, y := elliptic.UnmarshalCompressed(elliptic.P256(), m.PublicKey) + if x == nil || y == nil { + return false + } + p = &ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } + } + return crypto.VerifyRFC6979(p, m.Message, m.Data) == nil +}