scwallet

package
v1.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 26, 2020 License: GPL-3.0 Imports: 34 Imported by: 0

README

Using the smartcard wallet

Requirements

  • A USB smartcard reader
  • A keycard that supports the status app
  • PCSCD version 4.3 running on your system Only version 4.3 is currently supported

Preparing the smartcard

WARNING: FOILLOWING THESE INSTRUCTIONS WILL DESTROY THE MASTER KEY ON YOUR CARD. ONLY PROCEED IF NO FUNDS ARE ASSOCIATED WITH THESE ACCOUNTS

You can use status' keycard-cli and you should get at least version 2.1.1 of their smartcard application

You also need to make sure that the PCSC daemon is running on your system.

Then, you can install the application to the card by typing:

keycard install -a keycard_v2.2.1.cap && keycard init

At the end of this process, you will be provided with a PIN, a PUK and a pairing password. Write them down, you'll need them shortly.

Start geth with the console command. You will notice the following warning:

WARN [04-09|16:58:38.898] Failed to open wallet                    url=keycard://044def09                          err="smartcard: pairing password needed"

Write down the URL (keycard://044def09 in this example). Then ask geth to open the wallet:

> personal.openWallet("keycard://044def09")
Please enter the pairing password:

Enter the pairing password that you have received during card initialization. Same with the PIN that you will subsequently be asked for.

If everything goes well, you should see your new account when typing personal on the console:

> personal
WARN [04-09|17:02:07.330] Smartcard wallet account derivation failed url=keycard://044def09 err="Unexpected response status Cla=0x80, Ins=0xd1, Sw=0x6985"
{
  listAccounts: [],
  listWallets: [{
      status: "Empty, waiting for initialization",
      url: "keycard://044def09"
  }],
  ...
}

So the communication with the card is working, but there is no key associated with this wallet. Let's create it:

> personal.initializeWallet("keycard://044def09")
"tilt ... impact"

You should get a list of words, this is your seed so write them down. Your wallet should now be initialized:

> personal.listWallets
[{
  accounts: [{
      address: "0x678b7cd55c61917defb23546a41803c5bfefbc7a",
      url: "keycard://044d/m/44'/60'/0'/0/0"
  }],
  status: "Online",
  url: "keycard://044def09"
}]

You're all set!

Usage

  1. Start geth with the console command
  2. Check the card's URL by checking personal.listWallets:
  listWallets: [{
      status: "Online, can derive public keys",
      url: "keycard://a4d73015"
  }]
  1. Open the wallet, you will be prompted for your pairing password, then PIN:
personal.openWallet("keycard://a4d73015")
  1. Check that creation was successful by typing e.g. personal. Then use it like a regular wallet.

Known issues

  • Starting geth with a valid card seems to make firefox crash.
  • PCSC version 4.4 should work, but is currently untested

Documentation

Index

Constants

View Source
const (
	P1DeriveKeyFromMaster  = uint8(0x00)
	P1DeriveKeyFromParent  = uint8(0x01)
	P1DeriveKeyFromCurrent = uint8(0x10)
)

List of ADPU command parameters

View Source
const Scheme = "keycard"

Scheme is the URI prefix for smartcard wallets.

Variables

View Source
var (

	// DerivationSignatureHash is used to derive the public key from the signature of this hash
	DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes())
)
View Source
var ErrAlreadyOpen = errors.New("smartcard: already open")

ErrAlreadyOpen is returned if the smart card is attempted to be opened, but there is already a paired and unlocked session.

View Source
var ErrPINNeeded = errors.New("smartcard: pin needed")

ErrPINNeeded is returned if opening the smart card requires a PIN code. In this case, the calling application should request user input to enter the PIN and send it back.

View Source
var ErrPINUnblockNeeded = errors.New("smartcard: pin unblock needed")

ErrPINUnblockNeeded is returned if opening the smart card requires a PIN code, but all PIN attempts have already been exhausted. In this case the calling application should request user input for the PUK and a new PIN code to set fo the card.

View Source
var ErrPairingPasswordNeeded = errors.New("smartcard: pairing password needed")

ErrPairingPasswordNeeded is returned if opening the smart card requires pairing with a pairing password. In this case, the calling application should request user input to enter the pairing password and send it back.

View Source
var ErrPubkeyMismatch = errors.New("smartcard: recovered public key mismatch")

ErrPubkeyMismatch is returned if the public key recovered from a signature does not match the one expected by the user.

Functions

This section is empty.

Types

type Hub

type Hub struct {
	// contains filtered or unexported fields
}

Hub is a accounts.Backend that can find and handle generic PC/SC hardware wallets.

func NewHub

func NewHub(daemonPath string, scheme string, datadir string) (*Hub, error)

NewHub creates a new hardware wallet manager for smartcards.

func (*Hub) Subscribe

func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription

Subscribe implements accounts.Backend, creating an async subscription to receive notifications on the addition or removal of smart card wallets.

func (*Hub) Wallets

func (hub *Hub) Wallets() []accounts.Wallet

Wallets implements accounts.Backend, returning all the currently tracked smart cards that appear to be hardware wallets.

type SecureChannelSession

type SecureChannelSession struct {
	PairingKey []byte // A permanent shared secret for a pairing, if present

	PairingIndex uint8 // The pairing index
	// contains filtered or unexported fields
}

SecureChannelSession enables secure communication with a hardware wallet.

func NewSecureChannelSession

func NewSecureChannelSession(card *pcsc.Card, keyData []byte) (*SecureChannelSession, error)

NewSecureChannelSession creates a new secure channel for the given card and public key.

func (*SecureChannelSession) Open

func (s *SecureChannelSession) Open() error

Open initializes the secure channel.

func (*SecureChannelSession) Pair

func (s *SecureChannelSession) Pair(pairingPassword []byte) error

Pair establishes a new pairing with the smartcard.

func (*SecureChannelSession) Unpair

func (s *SecureChannelSession) Unpair() error

Unpair disestablishes an existing pairing.

type Session

type Session struct {
	Wallet  *Wallet               // A handle to the wallet that opened the session
	Channel *SecureChannelSession // A secure channel for encrypted messages
	// contains filtered or unexported fields
}

Session represents a secured communication session with the wallet.

type Wallet

type Wallet struct {
	Hub       *Hub   // A handle to the Hub that instantiated this wallet.
	PublicKey []byte // The wallet's public key (used for communication and identification, not signing!)
	// contains filtered or unexported fields
}

Wallet represents a smartcard wallet instance.

func NewWallet

func NewWallet(hub *Hub, card *pcsc.Card) *Wallet

NewWallet constructs and returns a new Wallet instance.

func (*Wallet) Accounts

func (w *Wallet) Accounts() []accounts.Account

Accounts retrieves the list of signing accounts the wallet is currently aware of. For hierarchical deterministic wallets, the list will not be exhaustive, rather only contain the accounts explicitly pinned during account derivation.

func (*Wallet) Close

func (w *Wallet) Close() error

Close stops and closes the wallet, freeing any resources.

func (*Wallet) Contains

func (w *Wallet) Contains(account accounts.Account) bool

Contains returns whether an account is part of this particular wallet or not.

func (*Wallet)