Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
aab35600
Unverified
Commit
aab35600
authored
Mar 22, 2021
by
MrChico
Committed by
GitHub
Mar 22, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
accounts: eip-712 signing for ledger (#22378)
* accounts: eip-712 signing for ledger * address review comments
parent
eaccdba4
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
128 additions
and
1 deletion
+128
-1
ledger.go
accounts/usbwallet/ledger.go
+82
-0
trezor.go
accounts/usbwallet/trezor.go
+4
-0
wallet.go
accounts/usbwallet/wallet.go
+42
-1
No files found.
accounts/usbwallet/ledger.go
View file @
aab35600
...
...
@@ -52,8 +52,10 @@ const (
ledgerOpRetrieveAddress
ledgerOpcode
=
0x02
// Returns the public key and Ethereum address for a given BIP 32 path
ledgerOpSignTransaction
ledgerOpcode
=
0x04
// Signs an Ethereum transaction after having the user validate the parameters
ledgerOpGetConfiguration
ledgerOpcode
=
0x06
// Returns specific wallet application configuration
ledgerOpSignTypedMessage
ledgerOpcode
=
0x0c
// Signs an Ethereum message following the EIP 712 specification
ledgerP1DirectlyFetchAddress
ledgerParam1
=
0x00
// Return address directly from the wallet
ledgerP1InitTypedMessageData
ledgerParam1
=
0x00
// First chunk of Typed Message data
ledgerP1InitTransactionData
ledgerParam1
=
0x00
// First transaction data block for signing
ledgerP1ContTransactionData
ledgerParam1
=
0x80
// Subsequent transaction data block for signing
ledgerP2DiscardAddressChainCode
ledgerParam2
=
0x00
// Do not return the chain code along with the address
...
...
@@ -170,6 +172,24 @@ func (w *ledgerDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
return
w
.
ledgerSign
(
path
,
tx
,
chainID
)
}
// SignTypedMessage implements usbwallet.driver, sending the message to the Ledger and
// waiting for the user to sign or deny the transaction.
//
// Note: this was introduced in the ledger 1.5.0 firmware
func
(
w
*
ledgerDriver
)
SignTypedMessage
(
path
accounts
.
DerivationPath
,
domainHash
[]
byte
,
messageHash
[]
byte
)
([]
byte
,
error
)
{
// If the Ethereum app doesn't run, abort
if
w
.
offline
()
{
return
nil
,
accounts
.
ErrWalletClosed
}
// Ensure the wallet is capable of signing the given transaction
if
w
.
version
[
0
]
<
1
&&
w
.
version
[
1
]
<
5
{
//lint:ignore ST1005 brand name displayed on the console
return
nil
,
fmt
.
Errorf
(
"Ledger version >= 1.5.0 required for EIP-712 signing (found version v%d.%d.%d)"
,
w
.
version
[
0
],
w
.
version
[
1
],
w
.
version
[
2
])
}
// All infos gathered and metadata checks out, request signing
return
w
.
ledgerSignTypedMessage
(
path
,
domainHash
,
messageHash
)
}
// ledgerVersion retrieves the current version of the Ethereum wallet app running
// on the Ledger wallet.
//
...
...
@@ -367,6 +387,68 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
return
sender
,
signed
,
nil
}
// ledgerSignTypedMessage sends the transaction to the Ledger wallet, and waits for the user
// to confirm or deny the transaction.
//
// The signing protocol is defined as follows:
//
// CLA | INS | P1 | P2 | Lc | Le
// ----+-----+----+-----------------------------+-----+---
// E0 | 0C | 00 | implementation version : 00 | variable | variable
//
// Where the input is:
//
// Description | Length
// -------------------------------------------------+----------
// Number of BIP 32 derivations to perform (max 10) | 1 byte
// First derivation index (big endian) | 4 bytes
// ... | 4 bytes
// Last derivation index (big endian) | 4 bytes
// domain hash | 32 bytes
// message hash | 32 bytes
//
//
//
// And the output data is:
//
// Description | Length
// ------------+---------
// signature V | 1 byte
// signature R | 32 bytes
// signature S | 32 bytes
func
(
w
*
ledgerDriver
)
ledgerSignTypedMessage
(
derivationPath
[]
uint32
,
domainHash
[]
byte
,
messageHash
[]
byte
)
([]
byte
,
error
)
{
// Flatten the derivation path into the Ledger request
path
:=
make
([]
byte
,
1
+
4
*
len
(
derivationPath
))
path
[
0
]
=
byte
(
len
(
derivationPath
))
for
i
,
component
:=
range
derivationPath
{
binary
.
BigEndian
.
PutUint32
(
path
[
1
+
4
*
i
:
],
component
)
}
// Create the 712 message
payload
:=
append
(
path
,
domainHash
...
)
payload
=
append
(
payload
,
messageHash
...
)
// Send the request and wait for the response
var
(
op
=
ledgerP1InitTypedMessageData
reply
[]
byte
err
error
)
// Send the message over, ensuring it's processed correctly
reply
,
err
=
w
.
ledgerExchange
(
ledgerOpSignTypedMessage
,
op
,
0
,
payload
)
if
err
!=
nil
{
return
nil
,
err
}
// Extract the Ethereum signature and do a sanity validation
if
len
(
reply
)
!=
crypto
.
SignatureLength
{
return
nil
,
errors
.
New
(
"reply lacks signature"
)
}
signature
:=
append
(
reply
[
1
:
],
reply
[
0
])
return
signature
,
nil
}
// ledgerExchange performs a data exchange with the Ledger wallet, sending it a
// message and retrieving the response.
//
...
...
accounts/usbwallet/trezor.go
View file @
aab35600
...
...
@@ -185,6 +185,10 @@ func (w *trezorDriver) SignTx(path accounts.DerivationPath, tx *types.Transactio
return
w
.
trezorSign
(
path
,
tx
,
chainID
)
}
func
(
w
*
trezorDriver
)
SignTypedMessage
(
path
accounts
.
DerivationPath
,
domainHash
[]
byte
,
messageHash
[]
byte
)
([]
byte
,
error
)
{
return
nil
,
accounts
.
ErrNotSupported
}
// trezorDerive sends a derivation request to the Trezor device and returns the
// Ethereum address located on that path.
func
(
w
*
trezorDriver
)
trezorDerive
(
derivationPath
[]
uint32
)
(
common
.
Address
,
error
)
{
...
...
accounts/usbwallet/wallet.go
View file @
aab35600
...
...
@@ -67,6 +67,8 @@ type driver interface {
// SignTx sends the transaction to the USB device and waits for the user to confirm
// or deny the transaction.
SignTx
(
path
accounts
.
DerivationPath
,
tx
*
types
.
Transaction
,
chainID
*
big
.
Int
)
(
common
.
Address
,
*
types
.
Transaction
,
error
)
SignTypedMessage
(
path
accounts
.
DerivationPath
,
messageHash
[]
byte
,
domainHash
[]
byte
)
([]
byte
,
error
)
}
// wallet represents the common functionality shared by all USB hardware
...
...
@@ -524,7 +526,46 @@ func (w *wallet) signHash(account accounts.Account, hash []byte) ([]byte, error)
// SignData signs keccak256(data). The mimetype parameter describes the type of data being signed
func
(
w
*
wallet
)
SignData
(
account
accounts
.
Account
,
mimeType
string
,
data
[]
byte
)
([]
byte
,
error
)
{
return
w
.
signHash
(
account
,
crypto
.
Keccak256
(
data
))
// Unless we are doing 712 signing, simply dispatch to signHash
if
!
(
mimeType
==
accounts
.
MimetypeTypedData
&&
len
(
data
)
==
66
&&
data
[
0
]
==
0x19
&&
data
[
1
]
==
0x01
)
{
return
w
.
signHash
(
account
,
crypto
.
Keccak256
(
data
))
}
// dispatch to 712 signing if the mimetype is TypedData and the format matches
w
.
stateLock
.
RLock
()
// Comms have own mutex, this is for the state fields
defer
w
.
stateLock
.
RUnlock
()
// If the wallet is closed, abort
if
w
.
device
==
nil
{
return
nil
,
accounts
.
ErrWalletClosed
}
// Make sure the requested account is contained within
path
,
ok
:=
w
.
paths
[
account
.
Address
]
if
!
ok
{
return
nil
,
accounts
.
ErrUnknownAccount
}
// All infos gathered and metadata checks out, request signing
<-
w
.
commsLock
defer
func
()
{
w
.
commsLock
<-
struct
{}{}
}()
// Ensure the device isn't screwed with while user confirmation is pending
// TODO(karalabe): remove if hotplug lands on Windows
w
.
hub
.
commsLock
.
Lock
()
w
.
hub
.
commsPend
++
w
.
hub
.
commsLock
.
Unlock
()
defer
func
()
{
w
.
hub
.
commsLock
.
Lock
()
w
.
hub
.
commsPend
--
w
.
hub
.
commsLock
.
Unlock
()
}()
// Sign the transaction
signature
,
err
:=
w
.
driver
.
SignTypedMessage
(
path
,
data
[
2
:
34
],
data
[
34
:
66
])
if
err
!=
nil
{
return
nil
,
err
}
return
signature
,
nil
}
// SignDataWithPassphrase implements accounts.Wallet, attempting to sign the given
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment