Skip to content

Commit

Permalink
accounts/usbwallet: mitigate ledger app chunking issue (#26773)
Browse files Browse the repository at this point in the history
This PR mitigates an issue with Ledger's on-device RLP deserialization, see
LedgerHQ/app-ethereum#409

Ledger's RLP deserialization code does not validate the length of the RLP list received,
and it may prematurely enter the signing flow when a APDU chunk boundary falls immediately
before the EIP-155 chain_id when deserializing a transaction. Since the chain_id is
uninitialized, it is 0 during this signing flow. This may cause the user to accidentally
sign the transaction with chain_id = 0. That signature would be returned from the device 1
packet earlier than expected by the communication loop. The device blocks the
second-to-last packet waiting for the signer flow, and then errors on the successive
packet (which contains the chain_id, zeroed r, and zeroed s)

Since the signature's early arrival causes successive errors during the communication
process, geth does not parse the improper signature produced by the device, and therefore
no improperly-signed transaction can be created. User funds are not at risk.

We mitigate by selecting the highest chunk size that leaves at least 4 bytes in the
final chunk.
  • Loading branch information
prestwich committed Mar 7, 2023
1 parent 41af42e commit 1e3177d
Showing 1 changed file with 9 additions and 1 deletion.
10 changes: 9 additions & 1 deletion accounts/usbwallet/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ const (
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

ledgerEip155Size int = 3 // Size of the EIP-155 chain_id,r,s in unsigned transactions
)

// errLedgerReplyInvalidHeader is the error message returned by a Ledger data exchange
Expand Down Expand Up @@ -347,9 +349,15 @@ func (w *ledgerDriver) ledgerSign(derivationPath []uint32, tx *types.Transaction
op = ledgerP1InitTransactionData
reply []byte
)

// Chunk size selection to mitigate an underlying RLP deserialization issue on the ledger app.
// https://github.com/LedgerHQ/app-ethereum/issues/409
chunk := 255
for ; len(payload)%chunk <= ledgerEip155Size; chunk-- {
}

for len(payload) > 0 {
// Calculate the size of the next data chunk
chunk := 255
if chunk > len(payload) {
chunk = len(payload)
}
Expand Down

0 comments on commit 1e3177d

Please sign in to comment.