aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/usbwallet/trezor.go
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/usbwallet/trezor.go')
-rw-r--r--accounts/usbwallet/trezor.go64
1 files changed, 45 insertions, 19 deletions
diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go
index a9d2e9959..82525a20c 100644
--- a/accounts/usbwallet/trezor.go
+++ b/accounts/usbwallet/trezor.go
@@ -41,6 +41,9 @@ import (
// encoded passphrase.
var ErrTrezorPINNeeded = errors.New("trezor: pin needed")
+// ErrTrezorPassphraseNeeded is returned if opening the trezor requires a passphrase
+var ErrTrezorPassphraseNeeded = errors.New("trezor: passphrase needed")
+
// errTrezorReplyInvalidHeader is the error message returned by a Trezor data exchange
// if the device replies with a mismatching header. This usually means the device
// is in browser mode.
@@ -48,12 +51,13 @@ var errTrezorReplyInvalidHeader = errors.New("trezor: invalid reply header")
// trezorDriver implements the communication with a Trezor hardware wallet.
type trezorDriver struct {
- device io.ReadWriter // USB device connection to communicate through
- version [3]uint32 // Current version of the Trezor firmware
- label string // Current textual label of the Trezor device
- pinwait bool // Flags whether the device is waiting for PIN entry
- failure error // Any failure that would make the device unusable
- log log.Logger // Contextual logger to tag the trezor with its id
+ device io.ReadWriter // USB device connection to communicate through
+ version [3]uint32 // Current version of the Trezor firmware
+ label string // Current textual label of the Trezor device
+ pinwait bool // Flags whether the device is waiting for PIN entry
+ passphrasewait bool // Flags whether the device is waiting for passphrase entry
+ failure error // Any failure that would make the device unusable
+ log log.Logger // Contextual logger to tag the trezor with its id
}
// newTrezorDriver creates a new instance of a Trezor USB protocol driver.
@@ -79,7 +83,7 @@ func (w *trezorDriver) Status() (string, error) {
}
// Open implements usbwallet.driver, attempting to initialize the connection to
-// the Trezor hardware wallet. Initializing the Trezor is a two phase operation:
+// the Trezor hardware wallet. Initializing the Trezor is a two or three phase operation:
// * The first phase is to initialize the connection and read the wallet's
// features. This phase is invoked is the provided passphrase is empty. The
// device will display the pinpad as a result and will return an appropriate
@@ -87,11 +91,13 @@ func (w *trezorDriver) Status() (string, error) {
// * The second phase is to unlock access to the Trezor, which is done by the
// user actually providing a passphrase mapping a keyboard keypad to the pin
// number of the user (shuffled according to the pinpad displayed).
+// * If needed the device will ask for passphrase which will require calling
+// open again with the actual passphrase (3rd phase)
func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error {
w.device, w.failure = device, nil
// If phase 1 is requested, init the connection and wait for user callback
- if passphrase == "" {
+ if passphrase == "" && !w.passphrasewait {
// If we're already waiting for a PIN entry, insta-return
if w.pinwait {
return ErrTrezorPINNeeded
@@ -104,26 +110,46 @@ func (w *trezorDriver) Open(device io.ReadWriter, passphrase string) error {
w.version = [3]uint32{features.GetMajorVersion(), features.GetMinorVersion(), features.GetPatchVersion()}
w.label = features.GetLabel()
- // Do a manual ping, forcing the device to ask for its PIN
+ // Do a manual ping, forcing the device to ask for its PIN and Passphrase
askPin := true
- res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin}, new(trezor.PinMatrixRequest), new(trezor.Success))
+ askPassphrase := true
+ res, err := w.trezorExchange(&trezor.Ping{PinProtection: &askPin, PassphraseProtection: &askPassphrase}, new(trezor.PinMatrixRequest), new(trezor.PassphraseRequest), new(trezor.Success))
if err != nil {
return err
}
// Only return the PIN request if the device wasn't unlocked until now
- if res == 1 {
- return nil // Device responded with trezor.Success
+ switch res {
+ case 0:
+ w.pinwait = true
+ return ErrTrezorPINNeeded
+ case 1:
+ w.pinwait = false
+ w.passphrasewait = true
+ return ErrTrezorPassphraseNeeded
+ case 2:
+ return nil // responded with trezor.Success
}
- w.pinwait = true
- return ErrTrezorPINNeeded
}
// Phase 2 requested with actual PIN entry
- w.pinwait = false
-
- if _, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success)); err != nil {
- w.failure = err
- return err
+ if w.pinwait {
+ w.pinwait = false
+ res, err := w.trezorExchange(&trezor.PinMatrixAck{Pin: &passphrase}, new(trezor.Success), new(trezor.PassphraseRequest))
+ if err != nil {
+ w.failure = err
+ return err
+ }
+ if res == 1 {
+ w.passphrasewait = true
+ return ErrTrezorPassphraseNeeded
+ }
+ } else if w.passphrasewait {
+ w.passphrasewait = false
+ if _, err := w.trezorExchange(&trezor.PassphraseAck{Passphrase: &passphrase}, new(trezor.Success)); err != nil {
+ w.failure = err
+ return err
+ }
}
+
return nil
}