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