From 798866bac0951008017af4a81e1596068af2ce6f Mon Sep 17 00:00:00 2001 From: Paul Berg Date: Sat, 27 Oct 2018 10:42:18 +0200 Subject: [PATCH] Solved stringified address encoding issue --- accounts/accounts.go | 2 +- cmd/clef/audit.log | 9 +++++ signer/core/signed_data.go | 70 +++++++++++++++++++-------------- signer/core/signed_data_test.go | 19 +++++---- 4 files changed, 59 insertions(+), 41 deletions(-) diff --git a/accounts/accounts.go b/accounts/accounts.go index cb1eae2815..a0675ab7a6 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -109,7 +109,7 @@ type Wallet interface { // a password to decrypt the account, or a PIN code to verify the transaction), // an AuthNeededError instance will be returned, containing infos for the user // about which fields or actions are needed. The user may retry by providing - // the needed details via SignTxWithPassphrase, or by other means (e.g. unlock + // the needed details via SignHashWithPassphraseSignTxWithPassphrase, or by other means (e.g. unlock // the account in a keystore). SignTx(account Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) diff --git a/cmd/clef/audit.log b/cmd/clef/audit.log index 45814ac8cf..85b2cc1f8d 100644 --- a/cmd/clef/audit.log +++ b/cmd/clef/audit.log @@ -245,3 +245,12 @@ t=2018-10-25T14:22:59+0200 lvl=info msg=SignData api=signer type=response data t=2018-10-25T14:23:05+0200 lvl=info msg=SignData api=signer type=request metadata="{\"remote\":\"127.0.0.1:59342\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\",\"User-Agent\":\"PostmanRuntime/7.3.0\",\"Origin\":\"\"}" addr="0x66d76e6a80dc7d46d7ec1b79b15dfa34c3c6ef21 [chksum INVALID]" data=608af3436e40964b9f2c7214953a3f03685f62b8deadbeef content-type=text/validator t=2018-10-25T14:23:31+0200 lvl=info msg=Configured api=signer audit log=audit.log t=2018-10-25T14:23:55+0200 lvl=info msg=SignData api=signer type=request metadata="{\"remote\":\"127.0.0.1:61180\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\",\"User-Agent\":\"PostmanRuntime/7.3.0\",\"Origin\":\"\"}" addr="0x66d76e6a80dc7d46d7ec1b79b15dfa34c3c6ef21 [chksum INVALID]" data=608af3436e40964b9f2c7214953a3f03685f62b8deadbeef content-type=text/validator +t=2018-10-25T20:12:47+0200 lvl=info msg=Configured api=signer audit log=audit.log +t=2018-10-25T20:13:00+0200 lvl=info msg=SignData api=signer type=request metadata="{\"remote\":\"127.0.0.1:59607\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\",\"User-Agent\":\"PostmanRuntime/7.3.0\",\"Origin\":\"\"}" addr="0x66d76e6a80dc7d46d7ec1b79b15dfa34c3c6ef21 [chksum INVALID]" data=608af3436e40964b9f2c7214953a3f03685f62b8deadbeef content-type=text/validator +t=2018-10-25T20:34:51+0200 lvl=info msg=Configured api=signer audit log=audit.log +t=2018-10-25T20:34:53+0200 lvl=info msg=SignData api=signer type=request metadata="{\"remote\":\"127.0.0.1:62187\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\",\"User-Agent\":\"PostmanRuntime/7.3.0\",\"Origin\":\"\"}" addr="0x66d76e6a80dc7d46d7ec1b79b15dfa34c3c6ef21 [chksum INVALID]" data=608af3436e40964b9f2c7214953a3f03685f62b8deadbeef content-type=text/validator +t=2018-10-25T20:35:38+0200 lvl=info msg=Configured api=signer audit log=audit.log +t=2018-10-25T20:35:43+0200 lvl=info msg=SignData api=signer type=request metadata="{\"remote\":\"127.0.0.1:62300\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\",\"User-Agent\":\"PostmanRuntime/7.3.0\",\"Origin\":\"\"}" addr="0x66d76e6a80dc7d46d7ec1b79b15dfa34c3c6ef21 [chksum INVALID]" data=608af3436e40964b9f2c7214953a3f03685f62b8deadbeef content-type=text/validator +t=2018-10-25T20:41:50+0200 lvl=info msg=Configured api=signer audit log=audit.log +t=2018-10-25T20:42:06+0200 lvl=info msg=SignData api=signer type=request metadata="{\"remote\":\"127.0.0.1:63054\",\"local\":\"localhost:8550\",\"scheme\":\"HTTP/1.1\",\"User-Agent\":\"PostmanRuntime/7.3.0\",\"Origin\":\"\"}" addr="0x66d76e6a80dc7d46d7ec1b79b15dfa34c3c6ef21 [chksum INVALID]" data=608af3436e40964b9f2c7214953a3f03685f62b8deadbeef content-type=text/validator +t=2018-10-26T10:33:40+0200 lvl=info msg=Configured api=signer audit log=audit.log diff --git a/signer/core/signed_data.go b/signer/core/signed_data.go index 548438d355..eb5df4d893 100644 --- a/signer/core/signed_data.go +++ b/signer/core/signed_data.go @@ -63,11 +63,11 @@ type EIP712TypePriority struct { type EIP712Data = map[string]interface{} type EIP712Domain struct { - Name string `json:"name"` - Version string `json:"version"` - ChainId *big.Int `json:"chainId"` - VerifyingContract common.Address `json:"verifyingContract"` - Salt hexutil.Bytes `json:"salt"` + Name string `json:"name"` + Version string `json:"version"` + ChainId *big.Int `json:"chainId"` + VerifyingContract string `json:"verifyingContract"` + Salt hexutil.Bytes `json:"salt"` } const ( @@ -76,6 +76,7 @@ const ( TypeBytes = "bytes" TypeInt = "int" TypeString = "string" + TypeUint = "uint" ) // Sign receives a request and produces a signature @@ -151,6 +152,7 @@ func (api *SignerAPI) determineSignatureFormat(contentType string, addr common.M return nil, errors.New("no data to sign") } sighash, msg := SignTextValidator(data) + fmt.Printf("%s", sighash) req = &SignDataRequest{Rawdata: data, Message: msg, Hash: sighash, ContentType: mediaType} break case TextPlain.Mime: @@ -185,8 +187,8 @@ func (api *SignerAPI) determineSignatureFormat(contentType string, addr common.M // hash = keccak256("\x19\x00"${address}${data}). func SignTextValidator(data hexutil.Bytes) (hexutil.Bytes, string) { address := common.BytesToAddress(data[:common.AddressLength]) - message := data[common.AddressLength:len(data)-1] - hash := fmt.Sprintf("\x19\x00:%x%s", address, string(message)) + message := data[common.AddressLength:] + hash := fmt.Sprintf("\x19\x00%s%s", address, string(message)) return crypto.Keccak256(hexutil.Bytes(hash)), hash } @@ -335,20 +337,23 @@ func (typedData *TypedData) TypeHash(primaryType string) hexutil.Bytes { } func bytesValueOf(_interface interface{}) hexutil.Bytes { - bytesVal, ok := _interface.(hexutil.Bytes) + bytesValue, ok := _interface.(hexutil.Bytes) if ok { - return bytesVal + return bytesValue } switch reflect.TypeOf(_interface) { + case reflect.TypeOf(hexutil.Bytes{}): + return _interface.(hexutil.Bytes) + case reflect.TypeOf([]uint8{}): + return _interface.([]uint8) case reflect.TypeOf(string("")): return hexutil.Bytes(_interface.(string)) - break default: break } - panic(fmt.Errorf("unrecognized interface %v", _interface)) + panic(fmt.Errorf("unrecognized interface type %T", _interface)) return hexutil.Bytes{} } @@ -376,7 +381,7 @@ func (typedData *TypedData) EncodeData(primaryType string, data map[string]inter for i := 0; i < 12; i++ { bytesValue = append(bytesValue, 0) } - for _, _byte := range encValue.(common.Address) { + for _, _byte := range common.HexToAddress(encValue.(string)) { bytesValue = append(bytesValue, _byte) } primitiveEncValue = bytesValue @@ -575,19 +580,35 @@ func (types *EIP712Types) IsValid() error { } // isStandardType checks if the given type is a EIP712 conformant type -func isStandardTypeStr(typeStr string) bool { - standardTypes := []string{ +func isStandardTypeStr(encType string) bool { + // Atomic types + for _, standardType := range []string{ TypeAddress, TypeBool, TypeBytes, - TypeInt, TypeString, - } - for _, val := range standardTypes { - if strings.HasPrefix(typeStr, val) || strings.Contains(typeStr, val) { + } { + if standardType == encType { return true } } + + // Dynamic types + for _, standardType := range []string { + TypeBytes, + TypeInt, + TypeUint, + } { + if strings.HasPrefix(encType, standardType) { + return true + } + } + + // Reference types + if encType[len(encType)-1] == ']' { + return true + } + return false } @@ -627,15 +648,4 @@ func (domain *EIP712Domain) Map() map[string]interface{} { dataMap["salt"] = domain.Salt } return dataMap -} - -// PrintJson will be removed -func printJson(label string, output map[string]interface{}) { - jsonVal, err := json.MarshalIndent(output, "", " ") - if err != nil { - panic(err) - } - fmt.Printf("%s:", label) - fmt.Print(string(jsonVal)) - fmt.Print("\n\n") -} +} \ No newline at end of file diff --git a/signer/core/signed_data_test.go b/signer/core/signed_data_test.go index 1f2f0ce17a..f25699bb2d 100644 --- a/signer/core/signed_data_test.go +++ b/signer/core/signed_data_test.go @@ -76,18 +76,18 @@ var domainStandard = EIP712Domain{ "Ether Mail", "1", big.NewInt(1), - common.HexToAddress("0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"), + "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", nil, } var dataStandard = map[string]interface{}{ "from": map[string]interface{}{ "name": "Cow", - "wallet": common.HexToAddress("0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826"), + "wallet": "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", }, "to": map[string]interface{}{ "name": "Bob", - "wallet": common.HexToAddress("0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB"), + "wallet": "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", }, "contents": "Hello, Bob!", } @@ -148,37 +148,36 @@ func TestSignData(t *testing.T) { if signature == nil || len(signature) != 65 { t.Errorf("Expected 65 byte signature (got %d bytes)", len(signature)) } - // TODO: test signature r,s,v values } func TestHashStruct(t *testing.T) { mainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.HashStruct(typedData.PrimaryType, typedData.Message))) if mainHash != "0xc52c0ee5d84264471806290a3f2c4cecfc5490626bf912d01f240d7a274b371e" { - t.Fatal(fmt.Errorf("hashStruct result %s is incorrect", mainHash)) + t.Errorf("Expected different hashStruct result (got %s)", mainHash) } domainHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.HashStruct("EIP712Domain", typedData.Domain.Map()))) if domainHash != "0xf2cee375fa42b42143804025fc449deafd50cc031ca257e0b194a650a912090f" { - t.Fatal(fmt.Errorf("hashStruct result %s is incorrect", domainHash)) + t.Errorf("Expected different hashStruct result (got %s)", domainHash) } } func TestEncodeType(t *testing.T) { domainTypeEncoding := string(typedData.EncodeType("EIP712Domain")) if domainTypeEncoding != "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" { - t.Fatal(fmt.Errorf("encodeType result %s is incorrect", domainTypeEncoding)) + t.Errorf("Expected different encodeType result (got %s)", domainTypeEncoding) } mailTypeEncoding := string(typedData.EncodeType(typedData.PrimaryType)) if mailTypeEncoding != "Mail(Person from,Person to,string contents)Person(string name,address wallet)" { - t.Fatal(fmt.Errorf("encodeType result %s is incorrect", mailTypeEncoding)) + t.Errorf("Expected different encodeType result (got %s)", mailTypeEncoding) } } func TestTypeHash(t *testing.T) { mailTypeHash := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.TypeHash(typedData.PrimaryType))) if mailTypeHash != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2" { - t.Fatal(fmt.Errorf("typeHash result %s is incorrect", mailTypeHash)) + t.Errorf("Expected different typeHash result (got %s)", mailTypeHash) } } @@ -186,6 +185,6 @@ func TestEncodeData(t *testing.T) { dataEncoding := fmt.Sprintf("0x%s", common.Bytes2Hex(typedData.EncodeData(typedData.PrimaryType, typedData.Message))) if dataEncoding != "0xa0cedeb2dc280ba39b857546d74f5549c3a1d7bdc2dd96bf881f76108e23dac2fc71e5fa27ff56c350aa531bc129ebdf613b772b6604664f5d8dbe21b85eb0c8cd54f074a4af31b4411ff6a60c9719dbd559c221c8ac3492d9d872b041d703d1b5aadf3154a261abdd9086fc627b61efca26ae5702701d05cd2305f7c52a2fc8" { - t.Fatal(fmt.Errorf("encodeData result %s is incorrect", dataEncoding)) + t.Errorf("Expected different encodeData result (got %s)", dataEncoding) } }