github.com/devfans/go-ethereum@v1.5.10-0.20170326212234-7419d0c38291/accounts/usbwallet/ledger_wallet.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // This file contains the implementation for interacting with the Ledger hardware
    18  // wallets. The wire protocol spec can be found in the Ledger Blue GitHub repo:
    19  // https://raw.githubusercontent.com/LedgerHQ/blue-app-eth/master/doc/ethapp.asc
    20  
    21  package usbwallet
    22  
    23  import (
    24  	"context"
    25  	"encoding/binary"
    26  	"encoding/hex"
    27  	"errors"
    28  	"fmt"
    29  	"io"
    30  	"math/big"
    31  	"sync"
    32  	"time"
    33  
    34  	ethereum "github.com/ethereum/go-ethereum"
    35  	"github.com/ethereum/go-ethereum/accounts"
    36  	"github.com/ethereum/go-ethereum/common"
    37  	"github.com/ethereum/go-ethereum/common/hexutil"
    38  	"github.com/ethereum/go-ethereum/core/types"
    39  	"github.com/ethereum/go-ethereum/log"
    40  	"github.com/ethereum/go-ethereum/rlp"
    41  	"github.com/karalabe/hid"
    42  )
    43  
    44  // Maximum time between wallet health checks to detect USB unplugs.
    45  const ledgerHeartbeatCycle = time.Second
    46  
    47  // Minimum time to wait between self derivation attempts, even it the user is
    48  // requesting accounts like crazy.
    49  const ledgerSelfDeriveThrottling = time.Second
    50  
    51  // ledgerOpcode is an enumeration encoding the supported Ledger opcodes.
    52  type ledgerOpcode byte
    53  
    54  // ledgerParam1 is an enumeration encoding the supported Ledger parameters for
    55  // specific opcodes. The same parameter values may be reused between opcodes.
    56  type ledgerParam1 byte
    57  
    58  // ledgerParam2 is an enumeration encoding the supported Ledger parameters for
    59  // specific opcodes. The same parameter values may be reused between opcodes.
    60  type ledgerParam2 byte
    61  
    62  const (
    63  	ledgerOpRetrieveAddress  ledgerOpcode = 0x02 // Returns the public key and Ethereum address for a given BIP 32 path
    64  	ledgerOpSignTransaction  ledgerOpcode = 0x04 // Signs an Ethereum transaction after having the user validate the parameters
    65  	ledgerOpGetConfiguration ledgerOpcode = 0x06 // Returns specific wallet application configuration
    66  
    67  	ledgerP1DirectlyFetchAddress    ledgerParam1 = 0x00 // Return address directly from the wallet
    68  	ledgerP1ConfirmFetchAddress     ledgerParam1 = 0x01 // Require a user confirmation before returning the address
    69  	ledgerP1InitTransactionData     ledgerParam1 = 0x00 // First transaction data block for signing
    70  	ledgerP1ContTransactionData     ledgerParam1 = 0x80 // Subsequent transaction data block for signing
    71  	ledgerP2DiscardAddressChainCode ledgerParam2 = 0x00 // Do not return the chain code along with the address
    72  	ledgerP2ReturnAddressChainCode  ledgerParam2 = 0x01 // Require a user confirmation before returning the address
    73  )
    74  
    75  // errReplyInvalidHeader is the error message returned by a Ledger data exchange
    76  // if the device replies with a mismatching header. This usually means the device
    77  // is in browser mode.
    78  var errReplyInvalidHeader = errors.New("invalid reply header")
    79  
    80  // errInvalidVersionReply is the error message returned by a Ledger version retrieval
    81  // when a response does arrive, but it does not contain the expected data.
    82  var errInvalidVersionReply = errors.New("invalid version reply")
    83  
    84  // ledgerWallet represents a live USB Ledger hardware wallet.
    85  type ledgerWallet struct {
    86  	url *accounts.URL // Textual URL uniquely identifying this wallet
    87  
    88  	info    hid.DeviceInfo // Known USB device infos about the wallet
    89  	device  *hid.Device    // USB device advertising itself as a Ledger wallet
    90  	failure error          // Any failure that would make the device unusable
    91  
    92  	version  [3]byte                                    // Current version of the Ledger Ethereum app (zero if app is offline)
    93  	browser  bool                                       // Flag whether the Ledger is in browser mode (reply channel mismatch)
    94  	accounts []accounts.Account                         // List of derive accounts pinned on the Ledger
    95  	paths    map[common.Address]accounts.DerivationPath // Known derivation paths for signing operations
    96  
    97  	deriveNextPath accounts.DerivationPath   // Next derivation path for account auto-discovery
    98  	deriveNextAddr common.Address            // Next derived account address for auto-discovery
    99  	deriveChain    ethereum.ChainStateReader // Blockchain state reader to discover used account with
   100  	deriveReq      chan chan struct{}        // Channel to request a self-derivation on
   101  	deriveQuit     chan chan error           // Channel to terminate the self-deriver with
   102  
   103  	healthQuit chan chan error
   104  
   105  	// Locking a hardware wallet is a bit special. Since hardware devices are lower
   106  	// performing, any communication with them might take a non negligible amount of
   107  	// time. Worse still, waiting for user confirmation can take arbitrarily long,
   108  	// but exclusive communication must be upheld during. Locking the entire wallet
   109  	// in the mean time however would stall any parts of the system that don't want
   110  	// to communicate, just read some state (e.g. list the accounts).
   111  	//
   112  	// As such, a hardware wallet needs two locks to function correctly. A state
   113  	// lock can be used to protect the wallet's software-side internal state, which
   114  	// must not be held exlusively during hardware communication. A communication
   115  	// lock can be used to achieve exclusive access to the device itself, this one
   116  	// however should allow "skipping" waiting for operations that might want to
   117  	// use the device, but can live without too (e.g. account self-derivation).
   118  	//
   119  	// Since we have two locks, it's important to know how to properly use them:
   120  	//   - Communication requires the `device` to not change, so obtaining the
   121  	//     commsLock should be done after having a stateLock.
   122  	//   - Communication must not disable read access to the wallet state, so it
   123  	//     must only ever hold a *read* lock to stateLock.
   124  	commsLock chan struct{} // Mutex (buf=1) for the USB comms without keeping the state locked
   125  	stateLock sync.RWMutex  // Protects read and write access to the wallet struct fields
   126  
   127  	log log.Logger // Contextual logger to tag the ledger with its id
   128  }
   129  
   130  // URL implements accounts.Wallet, returning the URL of the Ledger device.
   131  func (w *ledgerWallet) URL() accounts.URL {
   132  	return *w.url // Immutable, no need for a lock
   133  }
   134  
   135  // Status implements accounts.Wallet, always whether the Ledger is opened, closed
   136  // or whether the Ethereum app was not started on it.
   137  func (w *ledgerWallet) Status() string {
   138  	w.stateLock.RLock() // No device communication, state lock is enough
   139  	defer w.stateLock.RUnlock()
   140  
   141  	if w.failure != nil {
   142  		return fmt.Sprintf("Failed: %v", w.failure)
   143  	}
   144  	if w.device == nil {
   145  		return "Closed"
   146  	}
   147  	if w.browser {
   148  		return "Ethereum app in browser mode"
   149  	}
   150  	if w.offline() {
   151  		return "Ethereum app offline"
   152  	}
   153  	return fmt.Sprintf("Ethereum app v%d.%d.%d online", w.version[0], w.version[1], w.version[2])
   154  }
   155  
   156  // offline returns whether the wallet and the Ethereum app is offline or not.
   157  //
   158  // The method assumes that the state lock is held!
   159  func (w *ledgerWallet) offline() bool {
   160  	return w.version == [3]byte{0, 0, 0}
   161  }
   162  
   163  // failed returns if the USB device wrapped by the wallet failed for some reason.
   164  // This is used by the device scanner to report failed wallets as departed.
   165  //
   166  // The method assumes that the state lock is *not* held!
   167  func (w *ledgerWallet) failed() bool {
   168  	w.stateLock.RLock() // No device communication, state lock is enough
   169  	defer w.stateLock.RUnlock()
   170  
   171  	return w.failure != nil
   172  }
   173  
   174  // Open implements accounts.Wallet, attempting to open a USB connection to the
   175  // Ledger hardware wallet. The Ledger does not require a user passphrase, so that
   176  // parameter is silently discarded.
   177  func (w *ledgerWallet) Open(passphrase string) error {
   178  	w.stateLock.Lock() // State lock is enough since there's no connection yet at this point
   179  	defer w.stateLock.Unlock()
   180  
   181  	// If the wallet was already opened, don't try to open again
   182  	if w.device != nil {
   183  		return accounts.ErrWalletAlreadyOpen
   184  	}
   185  	// Otherwise iterate over all USB devices and find this again (no way to directly do this)
   186  	device, err := w.info.Open()
   187  	if err != nil {
   188  		return err
   189  	}
   190  	// Wallet seems to be successfully opened, guess if the Ethereum app is running
   191  	w.device = device
   192  	w.commsLock = make(chan struct{}, 1)
   193  	w.commsLock <- struct{}{} // Enable lock
   194  
   195  	w.paths = make(map[common.Address]accounts.DerivationPath)
   196  
   197  	w.deriveReq = make(chan chan struct{})
   198  	w.deriveQuit = make(chan chan error)
   199  	w.healthQuit = make(chan chan error)
   200  
   201  	defer func() {
   202  		go w.heartbeat()
   203  		go w.selfDerive()
   204  	}()
   205  
   206  	if _, err = w.ledgerDerive(accounts.DefaultBaseDerivationPath); err != nil {
   207  		// Ethereum app is not running or in browser mode, nothing more to do, return
   208  		if err == errReplyInvalidHeader {
   209  			w.browser = true
   210  		}
   211  		return nil
   212  	}
   213  	// Try to resolve the Ethereum app's version, will fail prior to v1.0.2
   214  	if w.version, err = w.ledgerVersion(); err != nil {
   215  		w.version = [3]byte{1, 0, 0} // Assume worst case, can't verify if v1.0.0 or v1.0.1
   216  	}
   217  	return nil
   218  }
   219  
   220  // heartbeat is a health check loop for the Ledger wallets to periodically verify
   221  // whether they are still present or if they malfunctioned. It is needed because:
   222  //  - libusb on Windows doesn't support hotplug, so we can't detect USB unplugs
   223  //  - communication timeout on the Ledger requires a device power cycle to fix
   224  func (w *ledgerWallet) heartbeat() {
   225  	w.log.Debug("Ledger health-check started")
   226  	defer w.log.Debug("Ledger health-check stopped")
   227  
   228  	// Execute heartbeat checks until termination or error
   229  	var (
   230  		errc chan error
   231  		err  error
   232  	)
   233  	for errc == nil && err == nil {
   234  		// Wait until termination is requested or the heartbeat cycle arrives
   235  		select {
   236  		case errc = <-w.healthQuit:
   237  			// Termination requested
   238  			continue
   239  		case <-time.After(ledgerHeartbeatCycle):
   240  			// Heartbeat time
   241  		}
   242  		// Execute a tiny data exchange to see responsiveness
   243  		w.stateLock.RLock()
   244  		if w.device == nil {
   245  			// Terminated while waiting for the lock
   246  			w.stateLock.RUnlock()
   247  			continue
   248  		}
   249  		<-w.commsLock // Don't lock state while resolving version
   250  		_, err = w.ledgerVersion()
   251  		w.commsLock <- struct{}{}
   252  		w.stateLock.RUnlock()
   253  
   254  		if err != nil && err != errInvalidVersionReply {
   255  			w.stateLock.Lock() // Lock state to tear the wallet down
   256  			w.failure = err
   257  			w.close()
   258  			w.stateLock.Unlock()
   259  		}
   260  		// Ignore non hardware related errors
   261  		err = nil
   262  	}
   263  	// In case of error, wait for termination
   264  	if err != nil {
   265  		w.log.Debug("Ledger health-check failed", "err", err)
   266  		errc = <-w.healthQuit
   267  	}
   268  	errc <- err
   269  }
   270  
   271  // Close implements accounts.Wallet, closing the USB connection to the Ledger.
   272  func (w *ledgerWallet) Close() error {
   273  	// Ensure the wallet was opened
   274  	w.stateLock.RLock()
   275  	hQuit, dQuit := w.healthQuit, w.deriveQuit
   276  	w.stateLock.RUnlock()
   277  
   278  	// Terminate the health checks
   279  	var herr error
   280  	if hQuit != nil {
   281  		errc := make(chan error)
   282  		hQuit <- errc
   283  		herr = <-errc // Save for later, we *must* close the USB
   284  	}
   285  	// Terminate the self-derivations
   286  	var derr error
   287  	if dQuit != nil {
   288  		errc := make(chan error)
   289  		dQuit <- errc
   290  		derr = <-errc // Save for later, we *must* close the USB
   291  	}
   292  	// Terminate the device connection
   293  	w.stateLock.Lock()
   294  	defer w.stateLock.Unlock()
   295  
   296  	w.healthQuit = nil
   297  	w.deriveQuit = nil
   298  	w.deriveReq = nil
   299  
   300  	if err := w.close(); err != nil {
   301  		return err
   302  	}
   303  	if herr != nil {
   304  		return herr
   305  	}
   306  	return derr
   307  }
   308  
   309  // close is the internal wallet closer that terminates the USB connection and
   310  // resets all the fields to their defaults.
   311  //
   312  // Note, close assumes the state lock is held!
   313  func (w *ledgerWallet) close() error {
   314  	// Allow duplicate closes, especially for health-check failures
   315  	if w.device == nil {
   316  		return nil
   317  	}
   318  	// Close the device, clear everything, then return
   319  	w.device.Close()
   320  	w.device = nil
   321  
   322  	w.browser, w.version = false, [3]byte{}
   323  	w.accounts, w.paths = nil, nil
   324  
   325  	return nil
   326  }
   327  
   328  // Accounts implements accounts.Wallet, returning the list of accounts pinned to
   329  // the Ledger hardware wallet. If self-derivation was enabled, the account list
   330  // is periodically expanded based on current chain state.
   331  func (w *ledgerWallet) Accounts() []accounts.Account {
   332  	// Attempt self-derivation if it's running
   333  	reqc := make(chan struct{}, 1)
   334  	select {
   335  	case w.deriveReq <- reqc:
   336  		// Self-derivation request accepted, wait for it
   337  		<-reqc
   338  	default:
   339  		// Self-derivation offline, throttled or busy, skip
   340  	}
   341  	// Return whatever account list we ended up with
   342  	w.stateLock.RLock()
   343  	defer w.stateLock.RUnlock()
   344  
   345  	cpy := make([]accounts.Account, len(w.accounts))
   346  	copy(cpy, w.accounts)
   347  	return cpy
   348  }
   349  
   350  // selfDerive is an account derivation loop that upon request attempts to find
   351  // new non-zero accounts.
   352  func (w *ledgerWallet) selfDerive() {
   353  	w.log.Debug("Ledger self-derivation started")
   354  	defer w.log.Debug("Ledger self-derivation stopped")
   355  
   356  	// Execute self-derivations until termination or error
   357  	var (
   358  		reqc chan struct{}
   359  		errc chan error
   360  		err  error
   361  	)
   362  	for errc == nil && err == nil {
   363  		// Wait until either derivation or termination is requested
   364  		select {
   365  		case errc = <-w.deriveQuit:
   366  			// Termination requested
   367  			continue
   368  		case reqc = <-w.deriveReq:
   369  			// Account discovery requested
   370  		}
   371  		// Derivation needs a chain and device access, skip if either unavailable
   372  		w.stateLock.RLock()
   373  		if w.device == nil || w.deriveChain == nil || w.offline() {
   374  			w.stateLock.RUnlock()
   375  			reqc <- struct{}{}
   376  			continue
   377  		}
   378  		select {
   379  		case <-w.commsLock:
   380  		default:
   381  			w.stateLock.RUnlock()
   382  			reqc <- struct{}{}
   383  			continue
   384  		}
   385  		// Device lock obtained, derive the next batch of accounts
   386  		var (
   387  			accs  []accounts.Account
   388  			paths []accounts.DerivationPath
   389  
   390  			nextAddr = w.deriveNextAddr
   391  			nextPath = w.deriveNextPath
   392  
   393  			context = context.Background()
   394  		)
   395  		for empty := false; !empty; {
   396  			// Retrieve the next derived Ethereum account
   397  			if nextAddr == (common.Address{}) {
   398  				if nextAddr, err = w.ledgerDerive(nextPath); err != nil {
   399  					w.log.Warn("Ledger account derivation failed", "err", err)
   400  					break
   401  				}
   402  			}
   403  			// Check the account's status against the current chain state
   404  			var (
   405  				balance *big.Int
   406  				nonce   uint64
   407  			)
   408  			balance, err = w.deriveChain.BalanceAt(context, nextAddr, nil)
   409  			if err != nil {
   410  				w.log.Warn("Ledger balance retrieval failed", "err", err)
   411  				break
   412  			}
   413  			nonce, err = w.deriveChain.NonceAt(context, nextAddr, nil)
   414  			if err != nil {
   415  				w.log.Warn("Ledger nonce retrieval failed", "err", err)
   416  				break
   417  			}
   418  			// If the next account is empty, stop self-derivation, but add it nonetheless
   419  			if balance.Sign() == 0 && nonce == 0 {
   420  				empty = true
   421  			}
   422  			// We've just self-derived a new account, start tracking it locally
   423  			path := make(accounts.DerivationPath, len(nextPath))
   424  			copy(path[:], nextPath[:])
   425  			paths = append(paths, path)
   426  
   427  			account := accounts.Account{
   428  				Address: nextAddr,
   429  				URL:     accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
   430  			}
   431  			accs = append(accs, account)
   432  
   433  			// Display a log message to the user for new (or previously empty accounts)
   434  			if _, known := w.paths[nextAddr]; !known || (!empty && nextAddr == w.deriveNextAddr) {
   435  				w.log.Info("Ledger discovered new account", "address", nextAddr, "path", path, "balance", balance, "nonce", nonce)
   436  			}
   437  			// Fetch the next potential account
   438  			if !empty {
   439  				nextAddr = common.Address{}
   440  				nextPath[len(nextPath)-1]++
   441  			}
   442  		}
   443  		// Self derivation complete, release device lock
   444  		w.commsLock <- struct{}{}
   445  		w.stateLock.RUnlock()
   446  
   447  		// Insert any accounts successfully derived
   448  		w.stateLock.Lock()
   449  		for i := 0; i < len(accs); i++ {
   450  			if _, ok := w.paths[accs[i].Address]; !ok {
   451  				w.accounts = append(w.accounts, accs[i])
   452  				w.paths[accs[i].Address] = paths[i]
   453  			}
   454  		}
   455  		// Shift the self-derivation forward
   456  		// TODO(karalabe): don't overwrite changes from wallet.SelfDerive
   457  		w.deriveNextAddr = nextAddr
   458  		w.deriveNextPath = nextPath
   459  		w.stateLock.Unlock()
   460  
   461  		// Notify the user of termination and loop after a bit of time (to avoid trashing)
   462  		reqc <- struct{}{}
   463  		if err == nil {
   464  			select {
   465  			case errc = <-w.deriveQuit:
   466  				// Termination requested, abort
   467  			case <-time.After(ledgerSelfDeriveThrottling):
   468  				// Waited enough, willing to self-derive again
   469  			}
   470  		}
   471  	}
   472  	// In case of error, wait for termination
   473  	if err != nil {
   474  		w.log.Debug("Ledger self-derivation failed", "err", err)
   475  		errc = <-w.deriveQuit
   476  	}
   477  	errc <- err
   478  }
   479  
   480  // Contains implements accounts.Wallet, returning whether a particular account is
   481  // or is not pinned into this Ledger instance. Although we could attempt to resolve
   482  // unpinned accounts, that would be an non-negligible hardware operation.
   483  func (w *ledgerWallet) Contains(account accounts.Account) bool {
   484  	w.stateLock.RLock()
   485  	defer w.stateLock.RUnlock()
   486  
   487  	_, exists := w.paths[account.Address]
   488  	return exists
   489  }
   490  
   491  // Derive implements accounts.Wallet, deriving a new account at the specific
   492  // derivation path. If pin is set to true, the account will be added to the list
   493  // of tracked accounts.
   494  func (w *ledgerWallet) Derive(path accounts.DerivationPath, pin bool) (accounts.Account, error) {
   495  	// Try to derive the actual account and update its URL if successful
   496  	w.stateLock.RLock() // Avoid device disappearing during derivation
   497  
   498  	if w.device == nil || w.offline() {
   499  		w.stateLock.RUnlock()
   500  		return accounts.Account{}, accounts.ErrWalletClosed
   501  	}
   502  	<-w.commsLock // Avoid concurrent hardware access
   503  	address, err := w.ledgerDerive(path)
   504  	w.commsLock <- struct{}{}
   505  
   506  	w.stateLock.RUnlock()
   507  
   508  	// If an error occurred or no pinning was requested, return
   509  	if err != nil {
   510  		return accounts.Account{}, err
   511  	}
   512  	account := accounts.Account{
   513  		Address: address,
   514  		URL:     accounts.URL{Scheme: w.url.Scheme, Path: fmt.Sprintf("%s/%s", w.url.Path, path)},
   515  	}
   516  	if !pin {
   517  		return account, nil
   518  	}
   519  	// Pinning needs to modify the state
   520  	w.stateLock.Lock()
   521  	defer w.stateLock.Unlock()
   522  
   523  	if _, ok := w.paths[address]; !ok {
   524  		w.accounts = append(w.accounts, account)
   525  		w.paths[address] = path
   526  	}
   527  	return account, nil
   528  }
   529  
   530  // SelfDerive implements accounts.Wallet, trying to discover accounts that the
   531  // user used previously (based on the chain state), but ones that he/she did not
   532  // explicitly pin to the wallet manually. To avoid chain head monitoring, self
   533  // derivation only runs during account listing (and even then throttled).
   534  func (w *ledgerWallet) SelfDerive(base accounts.DerivationPath, chain ethereum.ChainStateReader) {
   535  	w.stateLock.Lock()
   536  	defer w.stateLock.Unlock()
   537  
   538  	w.deriveNextPath = make(accounts.DerivationPath, len(base))
   539  	copy(w.deriveNextPath[:], base[:])
   540  
   541  	w.deriveNextAddr = common.Address{}
   542  	w.deriveChain = chain
   543  }
   544  
   545  // SignHash implements accounts.Wallet, however signing arbitrary data is not
   546  // supported for Ledger wallets, so this method will always return an error.
   547  func (w *ledgerWallet) SignHash(acc accounts.Account, hash []byte) ([]byte, error) {
   548  	return nil, accounts.ErrNotSupported
   549  }
   550  
   551  // SignTx implements accounts.Wallet. It sends the transaction over to the Ledger
   552  // wallet to request a confirmation from the user. It returns either the signed
   553  // transaction or a failure if the user denied the transaction.
   554  //
   555  // Note, if the version of the Ethereum application running on the Ledger wallet is
   556  // too old to sign EIP-155 transactions, but such is requested nonetheless, an error
   557  // will be returned opposed to silently signing in Homestead mode.
   558  func (w *ledgerWallet) SignTx(account accounts.Account, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   559  	w.stateLock.RLock() // Comms have own mutex, this is for the state fields
   560  	defer w.stateLock.RUnlock()
   561  
   562  	// If the wallet is closed, or the Ethereum app doesn't run, abort
   563  	if w.device == nil || w.offline() {
   564  		return nil, accounts.ErrWalletClosed
   565  	}
   566  	// Make sure the requested account is contained within
   567  	path, ok := w.paths[account.Address]
   568  	if !ok {
   569  		return nil, accounts.ErrUnknownAccount
   570  	}
   571  	// Ensure the wallet is capable of signing the given transaction
   572  	if chainID != nil && w.version[0] <= 1 && w.version[1] <= 0 && w.version[2] <= 2 {
   573  		return nil, fmt.Errorf("Ledger v%d.%d.%d doesn't support signing this transaction, please update to v1.0.3 at least", w.version[0], w.version[1], w.version[2])
   574  	}
   575  	// All infos gathered and metadata checks out, request signing
   576  	<-w.commsLock
   577  	defer func() { w.commsLock <- struct{}{} }()
   578  
   579  	return w.ledgerSign(path, account.Address, tx, chainID)
   580  }
   581  
   582  // SignHashWithPassphrase implements accounts.Wallet, however signing arbitrary
   583  // data is not supported for Ledger wallets, so this method will always return
   584  // an error.
   585  func (w *ledgerWallet) SignHashWithPassphrase(account accounts.Account, passphrase string, hash []byte) ([]byte, error) {
   586  	return nil, accounts.ErrNotSupported
   587  }
   588  
   589  // SignTxWithPassphrase implements accounts.Wallet, attempting to sign the given
   590  // transaction with the given account using passphrase as extra authentication.
   591  // Since the Ledger does not support extra passphrases, it is silently ignored.
   592  func (w *ledgerWallet) SignTxWithPassphrase(account accounts.Account, passphrase string, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   593  	return w.SignTx(account, tx, chainID)
   594  }
   595  
   596  // ledgerVersion retrieves the current version of the Ethereum wallet app running
   597  // on the Ledger wallet.
   598  //
   599  // The version retrieval protocol is defined as follows:
   600  //
   601  //   CLA | INS | P1 | P2 | Lc | Le
   602  //   ----+-----+----+----+----+---
   603  //    E0 | 06  | 00 | 00 | 00 | 04
   604  //
   605  // With no input data, and the output data being:
   606  //
   607  //   Description                                        | Length
   608  //   ---------------------------------------------------+--------
   609  //   Flags 01: arbitrary data signature enabled by user | 1 byte
   610  //   Application major version                          | 1 byte
   611  //   Application minor version                          | 1 byte
   612  //   Application patch version                          | 1 byte
   613  func (w *ledgerWallet) ledgerVersion() ([3]byte, error) {
   614  	// Send the request and wait for the response
   615  	reply, err := w.ledgerExchange(ledgerOpGetConfiguration, 0, 0, nil)
   616  	if err != nil {
   617  		return [3]byte{}, err
   618  	}
   619  	if len(reply) != 4 {
   620  		return [3]byte{}, errInvalidVersionReply
   621  	}
   622  	// Cache the version for future reference
   623  	var version [3]byte
   624  	copy(version[:], reply[1:])
   625  	return version, nil
   626  }
   627  
   628  // ledgerDerive retrieves the currently active Ethereum address from a Ledger
   629  // wallet at the specified derivation path.
   630  //
   631  // The address derivation protocol is defined as follows:
   632  //
   633  //   CLA | INS | P1 | P2 | Lc  | Le
   634  //   ----+-----+----+----+-----+---
   635  //    E0 | 02  | 00 return address
   636  //               01 display address and confirm before returning
   637  //                  | 00: do not return the chain code
   638  //                  | 01: return the chain code
   639  //                       | var | 00
   640  //
   641  // Where the input data is:
   642  //
   643  //   Description                                      | Length
   644  //   -------------------------------------------------+--------
   645  //   Number of BIP 32 derivations to perform (max 10) | 1 byte
   646  //   First derivation index (big endian)              | 4 bytes
   647  //   ...                                              | 4 bytes
   648  //   Last derivation index (big endian)               | 4 bytes
   649  //
   650  // And the output data is:
   651  //
   652  //   Description             | Length
   653  //   ------------------------+-------------------
   654  //   Public Key length       | 1 byte
   655  //   Uncompressed Public Key | arbitrary
   656  //   Ethereum address length | 1 byte
   657  //   Ethereum address        | 40 bytes hex ascii
   658  //   Chain code if requested | 32 bytes
   659  func (w *ledgerWallet) ledgerDerive(derivationPath []uint32) (common.Address, error) {
   660  	// Flatten the derivation path into the Ledger request
   661  	path := make([]byte, 1+4*len(derivationPath))
   662  	path[0] = byte(len(derivationPath))
   663  	for i, component := range derivationPath {
   664  		binary.BigEndian.PutUint32(path[1+4*i:], component)
   665  	}
   666  	// Send the request and wait for the response
   667  	reply, err := w.ledgerExchange(ledgerOpRetrieveAddress, ledgerP1DirectlyFetchAddress, ledgerP2DiscardAddressChainCode, path)
   668  	if err != nil {
   669  		return common.Address{}, err
   670  	}
   671  	// Discard the public key, we don't need that for now
   672  	if len(reply) < 1 || len(reply) < 1+int(reply[0]) {
   673  		return common.Address{}, errors.New("reply lacks public key entry")
   674  	}
   675  	reply = reply[1+int(reply[0]):]
   676  
   677  	// Extract the Ethereum hex address string
   678  	if len(reply) < 1 || len(reply) < 1+int(reply[0]) {
   679  		return common.Address{}, errors.New("reply lacks address entry")
   680  	}
   681  	hexstr := reply[1 : 1+int(reply[0])]
   682  
   683  	// Decode the hex sting into an Ethereum address and return
   684  	var address common.Address
   685  	hex.Decode(address[:], hexstr)
   686  	return address, nil
   687  }
   688  
   689  // ledgerSign sends the transaction to the Ledger wallet, and waits for the user
   690  // to confirm or deny the transaction.
   691  //
   692  // The transaction signing protocol is defined as follows:
   693  //
   694  //   CLA | INS | P1 | P2 | Lc  | Le
   695  //   ----+-----+----+----+-----+---
   696  //    E0 | 04  | 00: first transaction data block
   697  //               80: subsequent transaction data block
   698  //                  | 00 | variable | variable
   699  //
   700  // Where the input for the first transaction block (first 255 bytes) is:
   701  //
   702  //   Description                                      | Length
   703  //   -------------------------------------------------+----------
   704  //   Number of BIP 32 derivations to perform (max 10) | 1 byte
   705  //   First derivation index (big endian)              | 4 bytes
   706  //   ...                                              | 4 bytes
   707  //   Last derivation index (big endian)               | 4 bytes
   708  //   RLP transaction chunk                            | arbitrary
   709  //
   710  // And the input for subsequent transaction blocks (first 255 bytes) are:
   711  //
   712  //   Description           | Length
   713  //   ----------------------+----------
   714  //   RLP transaction chunk | arbitrary
   715  //
   716  // And the output data is:
   717  //
   718  //   Description | Length
   719  //   ------------+---------
   720  //   signature V | 1 byte
   721  //   signature R | 32 bytes
   722  //   signature S | 32 bytes
   723  func (w *ledgerWallet) ledgerSign(derivationPath []uint32, address common.Address, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) {
   724  	// Flatten the derivation path into the Ledger request
   725  	path := make([]byte, 1+4*len(derivationPath))
   726  	path[0] = byte(len(derivationPath))
   727  	for i, component := range derivationPath {
   728  		binary.BigEndian.PutUint32(path[1+4*i:], component)
   729  	}
   730  	// Create the transaction RLP based on whether legacy or EIP155 signing was requeste
   731  	var (
   732  		txrlp []byte
   733  		err   error
   734  	)
   735  	if chainID == nil {
   736  		if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data()}); err != nil {
   737  			return nil, err
   738  		}
   739  	} else {
   740  		if txrlp, err = rlp.EncodeToBytes([]interface{}{tx.Nonce(), tx.GasPrice(), tx.Gas(), tx.To(), tx.Value(), tx.Data(), chainID, big.NewInt(0), big.NewInt(0)}); err != nil {
   741  			return nil, err
   742  		}
   743  	}
   744  	payload := append(path, txrlp...)
   745  
   746  	// Send the request and wait for the response
   747  	var (
   748  		op    = ledgerP1InitTransactionData
   749  		reply []byte
   750  	)
   751  	for len(payload) > 0 {
   752  		// Calculate the size of the next data chunk
   753  		chunk := 255
   754  		if chunk > len(payload) {
   755  			chunk = len(payload)
   756  		}
   757  		// Send the chunk over, ensuring it's processed correctly
   758  		reply, err = w.ledgerExchange(ledgerOpSignTransaction, op, 0, payload[:chunk])
   759  		if err != nil {
   760  			return nil, err
   761  		}
   762  		// Shift the payload and ensure subsequent chunks are marked as such
   763  		payload = payload[chunk:]
   764  		op = ledgerP1ContTransactionData
   765  	}
   766  	// Extract the Ethereum signature and do a sanity validation
   767  	if len(reply) != 65 {
   768  		return nil, errors.New("reply lacks signature")
   769  	}
   770  	signature := append(reply[1:], reply[0])
   771  
   772  	// Create the correct signer and signature transform based on the chain ID
   773  	var signer types.Signer
   774  	if chainID == nil {
   775  		signer = new(types.HomesteadSigner)
   776  	} else {
   777  		signer = types.NewEIP155Signer(chainID)
   778  		signature[64] = signature[64] - byte(chainID.Uint64()*2+35)
   779  	}
   780  	// Inject the final signature into the transaction and sanity check the sender
   781  	signed, err := tx.WithSignature(signer, signature)
   782  	if err != nil {
   783  		return nil, err
   784  	}
   785  	sender, err := types.Sender(signer, signed)
   786  	if err != nil {
   787  		return nil, err
   788  	}
   789  	if sender != address {
   790  		return nil, fmt.Errorf("signer mismatch: expected %s, got %s", address.Hex(), sender.Hex())
   791  	}
   792  	return signed, nil
   793  }
   794  
   795  // ledgerExchange performs a data exchange with the Ledger wallet, sending it a
   796  // message and retrieving the response.
   797  //
   798  // The common transport header is defined as follows:
   799  //
   800  //  Description                           | Length
   801  //  --------------------------------------+----------
   802  //  Communication channel ID (big endian) | 2 bytes
   803  //  Command tag                           | 1 byte
   804  //  Packet sequence index (big endian)    | 2 bytes
   805  //  Payload                               | arbitrary
   806  //
   807  // The Communication channel ID allows commands multiplexing over the same
   808  // physical link. It is not used for the time being, and should be set to 0101
   809  // to avoid compatibility issues with implementations ignoring a leading 00 byte.
   810  //
   811  // The Command tag describes the message content. Use TAG_APDU (0x05) for standard
   812  // APDU payloads, or TAG_PING (0x02) for a simple link test.
   813  //
   814  // The Packet sequence index describes the current sequence for fragmented payloads.
   815  // The first fragment index is 0x00.
   816  //
   817  // APDU Command payloads are encoded as follows:
   818  //
   819  //  Description              | Length
   820  //  -----------------------------------
   821  //  APDU length (big endian) | 2 bytes
   822  //  APDU CLA                 | 1 byte
   823  //  APDU INS                 | 1 byte
   824  //  APDU P1                  | 1 byte
   825  //  APDU P2                  | 1 byte
   826  //  APDU length              | 1 byte
   827  //  Optional APDU data       | arbitrary
   828  func (w *ledgerWallet) ledgerExchange(opcode ledgerOpcode, p1 ledgerParam1, p2 ledgerParam2, data []byte) ([]byte, error) {
   829  	// Construct the message payload, possibly split into multiple chunks
   830  	apdu := make([]byte, 2, 7+len(data))
   831  
   832  	binary.BigEndian.PutUint16(apdu, uint16(5+len(data)))
   833  	apdu = append(apdu, []byte{0xe0, byte(opcode), byte(p1), byte(p2), byte(len(data))}...)
   834  	apdu = append(apdu, data...)
   835  
   836  	// Stream all the chunks to the device
   837  	header := []byte{0x01, 0x01, 0x05, 0x00, 0x00} // Channel ID and command tag appended
   838  	chunk := make([]byte, 64)
   839  	space := len(chunk) - len(header)
   840  
   841  	for i := 0; len(apdu) > 0; i++ {
   842  		// Construct the new message to stream
   843  		chunk = append(chunk[:0], header...)
   844  		binary.BigEndian.PutUint16(chunk[3:], uint16(i))
   845  
   846  		if len(apdu) > space {
   847  			chunk = append(chunk, apdu[:space]...)
   848  			apdu = apdu[space:]
   849  		} else {
   850  			chunk = append(chunk, apdu...)
   851  			apdu = nil
   852  		}
   853  		// Send over to the device
   854  		w.log.Trace("Data chunk sent to the Ledger", "chunk", hexutil.Bytes(chunk))
   855  		if _, err := w.device.Write(chunk); err != nil {
   856  			return nil, err
   857  		}
   858  	}
   859  	// Stream the reply back from the wallet in 64 byte chunks
   860  	var reply []byte
   861  	chunk = chunk[:64] // Yeah, we surely have enough space
   862  	for {
   863  		// Read the next chunk from the Ledger wallet
   864  		if _, err := io.ReadFull(w.device, chunk); err != nil {
   865  			return nil, err
   866  		}
   867  		w.log.Trace("Data chunk received from the Ledger", "chunk", hexutil.Bytes(chunk))
   868  
   869  		// Make sure the transport header matches
   870  		if chunk[0] != 0x01 || chunk[1] != 0x01 || chunk[2] != 0x05 {
   871  			return nil, errReplyInvalidHeader
   872  		}
   873  		// If it's the first chunk, retrieve the total message length
   874  		var payload []byte
   875  
   876  		if chunk[3] == 0x00 && chunk[4] == 0x00 {
   877  			reply = make([]byte, 0, int(binary.BigEndian.Uint16(chunk[5:7])))
   878  			payload = chunk[7:]
   879  		} else {
   880  			payload = chunk[5:]
   881  		}
   882  		// Append to the reply and stop when filled up
   883  		if left := cap(reply) - len(reply); left > len(payload) {
   884  			reply = append(reply, payload...)
   885  		} else {
   886  			reply = append(reply, payload[:left]...)
   887  			break
   888  		}
   889  	}
   890  	return reply[:len(reply)-2], nil
   891  }