diff --git a/accounts/hd.go b/accounts/hd.go index d14dbc842..574aa77f9 100644 --- a/accounts/hd.go +++ b/accounts/hd.go @@ -139,12 +139,12 @@ func (path DerivationPath) MarshalJSON() ([]byte, error) { return []byte(fmt.Sprintf("\"%s\"", path.String())), nil } -func (dp *DerivationPath) UnmarshalJSON(b []byte) error { - var path string +func (path *DerivationPath) UnmarshalJSON(b []byte) error { + var dp string var err error - if err = json.Unmarshal(b, &path); err != nil { + if err = json.Unmarshal(b, &dp); err != nil { return err } - *dp, err = ParseDerivationPath(path) + *path, err = ParseDerivationPath(dp) return err } diff --git a/accounts/scwallet/apdu.go b/accounts/scwallet/apdu.go index f9a34a91c..c7055c0cc 100644 --- a/accounts/scwallet/apdu.go +++ b/accounts/scwallet/apdu.go @@ -22,20 +22,20 @@ import ( ) const ( - CLA_ISO7816 = 0 + claISO7816 = 0 - INS_SELECT = 0xA4 - INS_GET_RESPONSE = 0xC0 - INS_PAIR = 0x12 - INS_UNPAIR = 0x13 - INS_OPEN_SECURE_CHANNEL = 0x10 - INS_MUTUALLY_AUTHENTICATE = 0x11 + insSelect = 0xA4 + insGetResponse = 0xC0 + insPair = 0x12 + insUnpair = 0x13 + insOpenSecureChannel = 0x10 + insMutuallyAuthenticate = 0x11 - SW1_GET_RESPONSE = 0x61 - SW1_OK = 0x90 + sw1GetResponse = 0x61 + sw1Ok = 0x90 ) -// CommandAPDU represents an application data unit sent to a smartcard +// CommandAPDU represents an application data unit sent to a smartcard. type CommandAPDU struct { Cla, Ins, P1, P2 uint8 // Class, Instruction, Parameter 1, Parameter 2 Data []byte // Command data @@ -72,13 +72,13 @@ func (ca CommandAPDU) serialize() ([]byte, error) { return buf.Bytes(), nil } -// ResponseAPDU represents an application data unit received from a smart card +// ResponseAPDU represents an application data unit received from a smart card. type ResponseAPDU struct { Data []byte // response data Sw1, Sw2 uint8 // status words 1 and 2 } -// deserialize deserializes a response APDU +// deserialize deserializes a response APDU. func (ra *ResponseAPDU) deserialize(data []byte) error { ra.Data = make([]byte, len(data)-2) diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index 6b81cd501..26aa6fc79 100644 --- a/accounts/scwallet/hub.go +++ b/accounts/scwallet/hub.go @@ -14,6 +14,22 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . +// This package implements support for smartcard-based hardware wallets such as +// the one written by Status: https://github.com/status-im/hardware-wallet +// +// This implementation of smartcard wallets have a different interaction process +// to other types of hardware wallet. The process works like this: +// +// 1. (First use with a given client) Establish a pairing between hardware +// wallet and client. This requires a secret value called a 'PUK'. You can +// pair with an unpaired wallet with `personal.openWallet(URI, PUK)`. +// 2. (First use only) Initialize the wallet, which generates a keypair, stores +// it on the wallet, and returns it so the user can back it up. You can +// initialize a wallet with `personal.initializeWallet(URI)`. +// 3. Connect to the wallet using the pairing information established in step 1. +// You can connect to a paired wallet with `personal.openWallet(URI, PIN)`. +// 4. Interact with the wallet as normal. + package scwallet import ( @@ -32,6 +48,7 @@ import ( "github.com/ethereum/go-ethereum/log" ) +// Scheme is the URI prefix for smartcard wallets. const Scheme = "pcsc" // refreshCycle is the maximum time between wallet refreshes (if USB hotplug @@ -41,9 +58,9 @@ const refreshCycle = 5 * time.Second // refreshThrottling is the minimum time between wallet refreshes to avoid thrashing. const refreshThrottling = 500 * time.Millisecond -// SmartcardPairing contains information about a smart card we have paired with -// or might pair withub. -type SmartcardPairing struct { +// smartcardPairing contains information about a smart card we have paired with +// or might pair with the hub. +type smartcardPairing struct { PublicKey []byte `json:"publicKey"` PairingIndex uint8 `json:"pairingIndex"` PairingKey []byte `json:"pairingKey"` @@ -56,7 +73,7 @@ type Hub struct { context *scard.Context datadir string - pairings map[string]SmartcardPairing + pairings map[string]smartcardPairing refreshed time.Time // Time instance when the list of wallets was last refreshed wallets map[string]*Wallet // Mapping from reader names to wallet instances updateFeed event.Feed // Event feed to notify wallet additions/removals @@ -71,7 +88,7 @@ type Hub struct { var HubType = reflect.TypeOf(&Hub{}) func (hub *Hub) readPairings() error { - hub.pairings = make(map[string]SmartcardPairing) + hub.pairings = make(map[string]smartcardPairing) pairingFile, err := os.Open(hub.datadir + "/smartcards.json") if err != nil { if os.IsNotExist(err) { @@ -84,7 +101,7 @@ func (hub *Hub) readPairings() error { if err != nil { return err } - var pairings []SmartcardPairing + var pairings []smartcardPairing if err := json.Unmarshal(pairingData, &pairings); err != nil { return err } @@ -101,7 +118,7 @@ func (hub *Hub) writePairings() error { return err } - pairings := make([]SmartcardPairing, 0, len(hub.pairings)) + pairings := make([]smartcardPairing, 0, len(hub.pairings)) for _, pairing := range hub.pairings { pairings = append(pairings, pairing) } @@ -118,7 +135,7 @@ func (hub *Hub) writePairings() error { return pairingFile.Close() } -func (hub *Hub) getPairing(wallet *Wallet) *SmartcardPairing { +func (hub *Hub) getPairing(wallet *Wallet) *smartcardPairing { pairing, ok := hub.pairings[string(wallet.PublicKey)] if ok { return &pairing @@ -126,7 +143,7 @@ func (hub *Hub) getPairing(wallet *Wallet) *SmartcardPairing { return nil } -func (hub *Hub) setPairing(wallet *Wallet, pairing *SmartcardPairing) error { +func (hub *Hub) setPairing(wallet *Wallet, pairing *smartcardPairing) error { if pairing == nil { delete(hub.pairings, string(wallet.PublicKey)) } else { @@ -158,7 +175,7 @@ func NewHub(scheme string, datadir string) (*Hub, error) { return hub, nil } -// Wallets implements accounts.Backend, returning all the currently tracked USB +// Wallets implements accounts.Backend, returning all the currently tracked // devices that appear to be hardware wallets. func (hub *Hub) Wallets() []accounts.Wallet { // Make sure the list of wallets is up to date @@ -176,7 +193,7 @@ func (hub *Hub) Wallets() []accounts.Wallet { return cpy } -// refreshWallets scans the USB devices attached to the machine and updates the +// refreshWallets scans the devices attached to the machine and updates the // list of wallets based on the found devices. func (hub *Hub) refreshWallets() { elapsed := time.Since(hub.refreshed) diff --git a/accounts/scwallet/securechannel.go b/accounts/scwallet/securechannel.go index f614362a9..752daf9b6 100644 --- a/accounts/scwallet/securechannel.go +++ b/accounts/scwallet/securechannel.go @@ -32,15 +32,15 @@ import ( ) const ( - MAX_PAYLOAD_SIZE = 223 - PAIR_P1_FIRST_STEP = 0 - PAIR_P1_LAST_STEP = 1 + maxPayloadSize = 223 + pairP1FirstStep = 0 + pairP1LastStep = 1 - SC_SECRET_LENGTH = 32 - SC_BLOCK_SIZE = 16 + scSecretLength = 32 + scBlockSize = 16 ) -// SecureChannelSession enables secure communication with a hardware wallet +// SecureChannelSession enables secure communication with a hardware wallet. type SecureChannelSession struct { card *scard.Card // A handle to the smartcard for communication secret []byte // A shared secret generated from our ECDSA keys @@ -52,7 +52,7 @@ type SecureChannelSession struct { PairingIndex uint8 // The pairing index } -// NewSecureChannelSession creates a new secure channel for the given card and public key +// NewSecureChannelSession creates a new secure channel for the given card and public key. func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSession, error) { // Generate an ECDSA keypair for ourselves gen := ecdh.NewEllipticECDH(crypto.S256()) @@ -78,7 +78,7 @@ func NewSecureChannelSession(card *scard.Card, keyData []byte) (*SecureChannelSe }, nil } -// Pair establishes a new pairing with the smartcard +// Pair establishes a new pairing with the smartcard. func (s *SecureChannelSession) Pair(sharedSecret []byte) error { secretHash := sha256.Sum256(sharedSecret) @@ -87,7 +87,7 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error { return err } - response, err := s.pair(PAIR_P1_FIRST_STEP, challenge) + response, err := s.pair(pairP1FirstStep, challenge) if err != nil { return err } @@ -107,7 +107,7 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error { md.Reset() md.Write(secretHash[:]) md.Write(cardChallenge) - response, err = s.pair(PAIR_P1_LAST_STEP, md.Sum(nil)) + response, err = s.pair(pairP1LastStep, md.Sum(nil)) if err != nil { return err } @@ -121,13 +121,13 @@ func (s *SecureChannelSession) Pair(sharedSecret []byte) error { return nil } -// Unpair disestablishes an existing pairing +// Unpair disestablishes an existing pairing. func (s *SecureChannelSession) Unpair() error { if s.PairingKey == nil { return fmt.Errorf("Cannot unpair: not paired") } - _, err := s.TransmitEncrypted(CLA_SCWALLET, INS_UNPAIR, s.PairingIndex, 0, []byte{}) + _, err := s.TransmitEncrypted(claSCWallet, insUnpair, s.PairingIndex, 0, []byte{}) if err != nil { return err } @@ -137,7 +137,7 @@ func (s *SecureChannelSession) Unpair() error { return nil } -// Open initializes the secure channel +// Open initializes the secure channel. func (s *SecureChannelSession) Open() error { if s.iv != nil { return fmt.Errorf("Session already opened") @@ -153,13 +153,13 @@ func (s *SecureChannelSession) Open() error { md := sha512.New() md.Write(s.secret) md.Write(s.PairingKey) - md.Write(response.Data[:SC_SECRET_LENGTH]) + md.Write(response.Data[:scSecretLength]) keyData := md.Sum(nil) - s.sessionEncKey = keyData[:SC_SECRET_LENGTH] - s.sessionMacKey = keyData[SC_SECRET_LENGTH : SC_SECRET_LENGTH*2] + s.sessionEncKey = keyData[:scSecretLength] + s.sessionMacKey = keyData[scSecretLength : scSecretLength*2] // The IV is the last bytes returned from the Open APDU. - s.iv = response.Data[SC_SECRET_LENGTH:] + s.iv = response.Data[scSecretLength:] if err := s.mutuallyAuthenticate(); err != nil { return err @@ -171,12 +171,12 @@ func (s *SecureChannelSession) Open() error { // mutuallyAuthenticate is an internal method to authenticate both ends of the // connection. func (s *SecureChannelSession) mutuallyAuthenticate() error { - data := make([]byte, SC_SECRET_LENGTH) + data := make([]byte, scSecretLength) if _, err := rand.Read(data); err != nil { return err } - response, err := s.TransmitEncrypted(CLA_SCWALLET, INS_MUTUALLY_AUTHENTICATE, 0, 0, data) + response, err := s.TransmitEncrypted(claSCWallet, insMutuallyAuthenticate, 0, 0, data) if err != nil { return err } @@ -184,18 +184,18 @@ func (s *SecureChannelSession) mutuallyAuthenticate() error { return fmt.Errorf("Got unexpected response from MUTUALLY_AUTHENTICATE: 0x%x%x", response.Sw1, response.Sw2) } - if len(response.Data) != SC_SECRET_LENGTH { - return fmt.Errorf("Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), SC_SECRET_LENGTH) + if len(response.Data) != scSecretLength { + return fmt.Errorf("Response from MUTUALLY_AUTHENTICATE was %d bytes, expected %d", len(response.Data), scSecretLength) } return nil } -// open is an internal method that sends an open APDU +// open is an internal method that sends an open APDU. func (s *SecureChannelSession) open() (*ResponseAPDU, error) { return transmit(s.card, &CommandAPDU{ - Cla: CLA_SCWALLET, - Ins: INS_OPEN_SECURE_CHANNEL, + Cla: claSCWallet, + Ins: insOpenSecureChannel, P1: s.PairingIndex, P2: 0, Data: s.publicKey, @@ -203,11 +203,11 @@ func (s *SecureChannelSession) open() (*ResponseAPDU, error) { }) } -// pair is an internal method that sends a pair APDU +// pair is an internal method that sends a pair APDU. func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*ResponseAPDU, error) { return transmit(s.card, &CommandAPDU{ - Cla: CLA_SCWALLET, - Ins: INS_PAIR, + Cla: claSCWallet, + Ins: insPair, P1: p1, P2: 0, Data: data, @@ -215,7 +215,7 @@ func (s *SecureChannelSession) pair(p1 uint8, data []byte) (*ResponseAPDU, error }) } -// TransmitEncrypted sends an encrypted message, and decrypts and returns the response +// TransmitEncrypted sends an encrypted message, and decrypts and returns the response. func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []byte) (*ResponseAPDU, error) { if s.iv == nil { return nil, fmt.Errorf("Channel not open") @@ -225,7 +225,7 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b if err != nil { return nil, err } - meta := []byte{cla, ins, p1, p2, byte(len(data) + SC_BLOCK_SIZE), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + meta := []byte{cla, ins, p1, p2, byte(len(data) + scBlockSize), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} if err = s.updateIV(meta, data); err != nil { return nil, err } @@ -263,17 +263,17 @@ func (s *SecureChannelSession) TransmitEncrypted(cla, ins, p1, p2 byte, data []b rapdu := &ResponseAPDU{} rapdu.deserialize(plainData) - if rapdu.Sw1 != SW1_OK { + if rapdu.Sw1 != sw1Ok { return nil, fmt.Errorf("Unexpected response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", cla, ins, rapdu.Sw1, rapdu.Sw2) } return rapdu, nil } -// encryptAPDU is an internal method that serializes and encrypts an APDU +// encryptAPDU is an internal method that serializes and encrypts an APDU. func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) { - if len(data) > MAX_PAYLOAD_SIZE { - return nil, fmt.Errorf("Payload of %d bytes exceeds maximum of %d", len(data), MAX_PAYLOAD_SIZE) + if len(data) > maxPayloadSize { + return nil, fmt.Errorf("Payload of %d bytes exceeds maximum of %d", len(data), maxPayloadSize) } data = pad(data, 0x80) @@ -288,7 +288,7 @@ func (s *SecureChannelSession) encryptAPDU(data []byte) ([]byte, error) { return ret, nil } -// pad applies message padding to a 16 byte boundary +// pad applies message padding to a 16 byte boundary. func pad(data []byte, terminator byte) []byte { padded := make([]byte, (len(data)/16+1)*16) copy(padded, data) @@ -296,7 +296,7 @@ func pad(data []byte, terminator byte) []byte { return padded } -// decryptAPDU is an internal method that decrypts and deserializes an APDU +// decryptAPDU is an internal method that decrypts and deserializes an APDU. func (s *SecureChannelSession) decryptAPDU(data []byte) ([]byte, error) { a, err := aes.NewCipher(s.sessionEncKey) if err != nil { @@ -310,7 +310,7 @@ func (s *SecureChannelSession) decryptAPDU(data []byte) ([]byte, error) { return unpad(ret, 0x80) } -// unpad strips padding from a message +// unpad strips padding from a message. func unpad(data []byte, terminator byte) ([]byte, error) { for i := 1; i <= 16; i++ { switch data[len(data)-i] { diff --git a/accounts/scwallet/wallet.go b/accounts/scwallet/wallet.go index 8a8018c6e..c2cf93965 100644 --- a/accounts/scwallet/wallet.go +++ b/accounts/scwallet/wallet.go @@ -42,7 +42,7 @@ import ( ) var ( - APPLET_AID = []byte{0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x57, 0x61, 0x6C, 0x6C, 0x65, 0x74, 0x41, 0x70, 0x70} + appletAID = []byte{0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x57, 0x61, 0x6C, 0x6C, 0x65, 0x74, 0x41, 0x70, 0x70} AlreadyOpenError = errors.New("Wallet already open") PairingRequiredError = errors.New("Pairing required with personal.openWallet(puk)") PinRequiredError = errors.New("Must unlock with personal.openWallet(pin)") @@ -52,23 +52,23 @@ var ( ) const ( - CLA_SCWALLET = 0x80 - INS_VERIFY_PIN = 0x20 - INS_EXPORT_KEY = 0xC2 - INS_SIGN = 0xC0 - INS_LOAD_KEY = 0xD0 - INS_DERIVE_KEY = 0xD1 - INS_STATUS = 0xF2 - DERIVE_P1_ASSISTED = uint8(0x01) - DERIVE_P1_APPEND = uint8(0x80) - DERIVE_P2_KEY_PATH = uint8(0x00) - DERIVE_P2_PUBLIC_KEY = uint8(0x01) - STATUS_P1_WALLET_STATUS = uint8(0x00) - STATUS_P1_PATH = uint8(0x01) - SIGN_P1_PRECOMPUTED_HASH = uint8(0x01) - SIGN_P2_ONLY_BLOCK = uint8(0x81) - EXPORT_P1_ANY = uint8(0x00) - EXPORT_P2_PUBKEY = uint8(0x01) + claSCWallet = 0x80 + insVerifyPin = 0x20 + insExportKey = 0xC2 + insSign = 0xC0 + insLoadKey = 0xD0 + insDeriveKey = 0xD1 + insStatus = 0xF2 + deriveP1Assisted = uint8(0x01) + deriveP1Append = uint8(0x80) + deriveP2KeyPath = uint8(0x00) + deriveP2PublicKey = uint8(0x01) + statusP1WalletStatus = uint8(0x00) + statusP1Path = uint8(0x01) + signP1PrecomputedHash = uint8(0x01) + signP2OnlyBlock = uint8(0x81) + exportP1Any = uint8(0x00) + exportP2Pubkey = uint8(0x01) // Minimum time to wait between self derivation attempts, even it the user is // requesting accounts like crazy. @@ -120,10 +120,10 @@ func transmit(card *scard.Card, command *CommandAPDU) (*ResponseAPDU, error) { } // Are we being asked to fetch the response separately? - if response.Sw1 == SW1_GET_RESPONSE && (command.Cla != CLA_ISO7816 || command.Ins != INS_GET_RESPONSE) { + if response.Sw1 == sw1GetResponse && (command.Cla != claISO7816 || command.Ins != insGetResponse) { return transmit(card, &CommandAPDU{ - Cla: CLA_ISO7816, - Ins: INS_GET_RESPONSE, + Cla: claISO7816, + Ins: insGetResponse, P1: 0, P2: 0, Data: nil, @@ -131,7 +131,7 @@ func transmit(card *scard.Card, command *CommandAPDU) (*ResponseAPDU, error) { }) } - if response.Sw1 != SW1_OK { + if response.Sw1 != sw1Ok { return nil, fmt.Errorf("Unexpected insecure response status Cla=0x%x, Ins=0x%x, Sw=0x%x%x", command.Cla, command.Ins, response.Sw1, response.Sw2) } @@ -173,11 +173,11 @@ func (w *Wallet) connect() error { // doselect is an internal (unlocked) function to send a SELECT APDU to the card. func (w *Wallet) doselect() (*applicationInfo, error) { response, err := transmit(w.card, &CommandAPDU{ - Cla: CLA_ISO7816, - Ins: INS_SELECT, + Cla: claISO7816, + Ins: insSelect, P1: 4, P2: 0, - Data: APPLET_AID, + Data: appletAID, }) if err != nil { return nil, err @@ -685,7 +685,7 @@ func (w *Wallet) findAccountPath(account accounts.Account) (accounts.DerivationP return accounts.ParseDerivationPath(parts[1]) } -// Session represents a secured communication session with the wallet +// Session represents a secured communication session with the wallet. type Session struct { Wallet *Wallet // A handle to the wallet that opened the session Channel *SecureChannelSession // A secure channel for encrypted messages @@ -693,13 +693,13 @@ type Session struct { } // pair establishes a new pairing over this channel, using the provided secret. -func (s *Session) pair(secret []byte) (SmartcardPairing, error) { +func (s *Session) pair(secret []byte) (smartcardPairing, error) { err := s.Channel.Pair(secret) if err != nil { - return SmartcardPairing{}, err + return smartcardPairing{}, err } - return SmartcardPairing{ + return smartcardPairing{ PublicKey: s.Wallet.PublicKey, PairingIndex: s.Channel.PairingIndex, PairingKey: s.Channel.PairingKey, @@ -707,7 +707,7 @@ func (s *Session) pair(secret []byte) (SmartcardPairing, error) { }, nil } -// unpair deletes an existing pairing +// unpair deletes an existing pairing. func (s *Session) unpair() error { if !s.verified { return fmt.Errorf("Unpair requires that the PIN be verified") @@ -715,27 +715,27 @@ func (s *Session) unpair() error { return s.Channel.Unpair() } -// verifyPin unlocks a wallet with the provided pin +// verifyPin unlocks a wallet with the provided pin. func (s *Session) verifyPin(pin []byte) error { - if _, err := s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_VERIFY_PIN, 0, 0, pin); err != nil { + if _, err := s.Channel.TransmitEncrypted(claSCWallet, insVerifyPin, 0, 0, pin); err != nil { return err } s.verified = true return nil } -// release releases resources associated with the channel +// release releases resources associated with the channel. func (s *Session) release() error { return s.Wallet.card.Disconnect(scard.LeaveCard) } -// paired returns true if a valid pairing exists +// paired returns true if a valid pairing exists. func (s *Session) paired() bool { return s.Channel.PairingKey != nil } -// authenticate uses an existing pairing to establish a secure channel -func (s *Session) authenticate(pairing SmartcardPairing) error { +// authenticate uses an existing pairing to establish a secure channel. +func (s *Session) authenticate(pairing smartcardPairing) error { if !bytes.Equal(s.Wallet.PublicKey, pairing.PublicKey) { return fmt.Errorf("Cannot pair using another wallet's pairing; %x != %x", s.Wallet.PublicKey, pairing.PublicKey) } @@ -744,7 +744,7 @@ func (s *Session) authenticate(pairing SmartcardPairing) error { return s.Channel.Open() } -// walletStatus describes a smartcard wallet's status information +// walletStatus describes a smartcard wallet's status information. type walletStatus struct { PinRetryCount int // Number of remaining PIN retries PukRetryCount int // Number of remaining PUK retries @@ -756,9 +756,9 @@ func (w walletStatus) String() string { return fmt.Sprintf("pinRetryCount=%d, pukRetryCount=%d, initialized=%t, supportsPkDerivation=%t", w.PinRetryCount, w.PukRetryCount, w.Initialized, w.SupportsPKDerivation) } -// getWalletStatus fetches the wallet's status from the card +// getWalletStatus fetches the wallet's status from the card. func (s *Session) getWalletStatus() (*walletStatus, error) { - response, err := s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_STATUS, STATUS_P1_WALLET_STATUS, 0, nil) + response, err := s.Channel.TransmitEncrypted(claSCWallet, insStatus, statusP1WalletStatus, 0, nil) if err != nil { return nil, err } @@ -771,9 +771,9 @@ func (s *Session) getWalletStatus() (*walletStatus, error) { return status, nil } -// getDerivationPath fetches the wallet's current derivation path from the card +// getDerivationPath fetches the wallet's current derivation path from the card. func (s *Session) getDerivationPath() (accounts.DerivationPath, error) { - response, err := s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_STATUS, STATUS_P1_PATH, 0, nil) + response, err := s.Channel.TransmitEncrypted(claSCWallet, insStatus, statusP1Path, 0, nil) if err != nil { return nil, err } @@ -783,14 +783,14 @@ func (s *Session) getDerivationPath() (accounts.DerivationPath, error) { return path, binary.Read(buf, binary.BigEndian, &path) } -// initializeData contains data needed to initialize the smartcard wallet +// initializeData contains data needed to initialize the smartcard wallet. type initializeData struct { PublicKey []byte `asn1:"tag:0"` PrivateKey []byte `asn1:"tag:1"` ChainCode []byte `asn1:"tag:2"` } -// initialize initializes the card with new key data +// initialize initializes the card with new key data. func (s *Session) initialize(seed []byte) error { // HMAC the seed to produce the private key and chain code mac := hmac.New(sha512.New, []byte("Bitcoin seed")) @@ -814,11 +814,11 @@ func (s *Session) initialize(seed []byte) error { // Nasty hack to force the top-level struct tag to be context-specific data[0] = 0xA1 - _, err = s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_LOAD_KEY, 0x02, 0, data) + _, err = s.Channel.TransmitEncrypted(claSCWallet, insLoadKey, 0x02, 0, data) return err } -// derive derives a new HD key path on the card +// derive derives a new HD key path on the card. func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error) { // If the current path is a prefix of the desired path, we don't have to // start again. @@ -858,7 +858,7 @@ func (s *Session) derive(path accounts.DerivationPath) (accounts.Account, error) return s.Wallet.makeAccount(crypto.PubkeyToAddress(*crypto.ToECDSAPub(pubkey)), path), nil } -// keyDerivationInfo contains information on the current key derivation step +// keyDerivationInfo contains information on the current key derivation step. type keyDerivationInfo struct { PublicKeyX []byte `asn1:"tag:3"` // The X coordinate of the current public key Signature struct { @@ -871,16 +871,16 @@ type keyDerivationInfo struct { // a specific path, and performing the necessary computations to finish the public key // generation step. func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, error) { - p1 := DERIVE_P1_ASSISTED + p1 := deriveP1Assisted if !reset { - p1 |= DERIVE_P1_APPEND + p1 |= deriveP1Append } buf := new(bytes.Buffer) if err := binary.Write(buf, binary.BigEndian, pathComponent); err != nil { return nil, err } - response, err := s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_DERIVE_KEY, p1, DERIVE_P2_KEY_PATH, buf.Bytes()) + response, err := s.Channel.TransmitEncrypted(claSCWallet, insDeriveKey, p1, deriveP2KeyPath, buf.Bytes()) if err != nil { return nil, err } @@ -900,7 +900,7 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e return nil, err } - _, err = s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_DERIVE_KEY, DERIVE_P1_ASSISTED|DERIVE_P1_APPEND, DERIVE_P2_PUBLIC_KEY, pubkey) + _, err = s.Channel.TransmitEncrypted(claSCWallet, insDeriveKey, deriveP1Assisted|deriveP1Append, deriveP2PublicKey, pubkey) if err != nil { return nil, err } @@ -908,15 +908,15 @@ func (s *Session) deriveKeyAssisted(reset bool, pathComponent uint32) ([]byte, e return pubkey, nil } -// keyExport contains information on an exported keypair +// keyExport contains information on an exported keypair. type keyExport struct { PublicKey []byte `asn1:"tag:0"` PrivateKey []byte `asn1:"tag:1,optional"` } -// getPublicKey returns the public key for the current derivation path +// getPublicKey returns the public key for the current derivation path. func (s *Session) getPublicKey() ([]byte, error) { - response, err := s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_EXPORT_KEY, EXPORT_P1_ANY, EXPORT_P2_PUBKEY, nil) + response, err := s.Channel.TransmitEncrypted(claSCWallet, insExportKey, exportP1Any, exportP2Pubkey, nil) if err != nil { return nil, err } @@ -930,7 +930,7 @@ func (s *Session) getPublicKey() ([]byte, error) { } // signatureData contains information on a signature - the signature itself and -// the corresponding public key +// the corresponding public key. type signatureData struct { PublicKey []byte `asn1:"tag:0"` Signature struct { @@ -949,7 +949,7 @@ func (s *Session) sign(path accounts.DerivationPath, hash []byte) ([]byte, error } deriveTime := time.Now() - response, err := s.Channel.TransmitEncrypted(CLA_SCWALLET, INS_SIGN, SIGN_P1_PRECOMPUTED_HASH, SIGN_P2_ONLY_BLOCK, hash) + response, err := s.Channel.TransmitEncrypted(claSCWallet, insSign, signP1PrecomputedHash, signP2OnlyBlock, hash) if err != nil { return nil, err } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 7938b264a..acb3e7075 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -473,6 +473,7 @@ func (s *PrivateAccountAPI) SignAndSendTransaction(ctx context.Context, args Sen return s.SendTransaction(ctx, args, passwd) } +// InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key. func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) { wallet, err := s.am.Wallet(url) if err != nil { @@ -499,6 +500,7 @@ func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (s } } +// Unpair deletes a pairing between wallet and geth. func (s *PrivateAccountAPI) Unpair(ctx context.Context, url string, pin string) error { wallet, err := s.am.Wallet(url) if err != nil {