From 2a3ba4fcc0335514ff4dc5c81115d4fb8c3c59f7 Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Mon, 18 Mar 2019 19:41:15 +0100 Subject: [PATCH] remove cmd --- cmd/keycard/README.md | 80 ------ cmd/keycard/initializer.go | 139 ----------- cmd/keycard/installer.go | 138 ----------- cmd/keycard/main.go | 288 ---------------------- cmd/keycard/shell.go | 485 ------------------------------------- 5 files changed, 1130 deletions(-) delete mode 100644 cmd/keycard/README.md delete mode 100644 cmd/keycard/initializer.go delete mode 100644 cmd/keycard/installer.go delete mode 100644 cmd/keycard/main.go delete mode 100644 cmd/keycard/shell.go diff --git a/cmd/keycard/README.md b/cmd/keycard/README.md deleted file mode 100644 index 933fc27..0000000 --- a/cmd/keycard/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# keycard - -`keycard` is a command line tool you can use to initialize a smartcard with the [Status Keycard](https://github.com/status-im/status-keycard). - -## Dependencies - -To install `keycard-go` you need `go` in your system. - -MacOSX: - -`brew install go` - -## Installation - -`go get -u github.com/status-im/keycard-go/cmd/keycard` - -The executable will be installed in `$GOPATH/bin`. -Check your `$GOPATH` with `go env`. - -## Usage - -### Install the keycard applet - -The install command will install an applet to the card. -You can download the status `cap` file from the [status-im/status-keycard releases page](https://github.com/status-im/status-keycard/releases). - -```bash -keycard install -l debug -a PATH_TO_CAP_FILE -``` - -In case the applet is already installed and you want to force a new installation you can pass the `-f` flag. - -### Card info - -```bash -keycard info -l debug -``` - -The `info` command will print something like this: - -``` -Installed: true -Initialized: false -InstanceUID: 0x -PublicKey: 0x112233... -Version: 0x -AvailableSlots: 0x -KeyUID: 0x -``` - -### Card initialization - - -```bash -keycard init -l debug -``` - -The `init` command initializes the card and generates the secrets needed to pair the card to a device. - -``` -PIN 123456 -PUK 123456789012 -Pairing password: RandomPairingPassword -``` - -### Deleting the applet from the card - -:warning: **WARNING! This command will remove the applet and all the keys from the card.** :warning: - -```bash -keycard delete -l debug -``` - -### Pairing - -```bash -keycard pair -l debug -``` - -The process will ask for `PairingPassword` and `PIN` and will generate a pairing key you can use to interact with the card. diff --git a/cmd/keycard/initializer.go b/cmd/keycard/initializer.go deleted file mode 100644 index d31a315..0000000 --- a/cmd/keycard/initializer.go +++ /dev/null @@ -1,139 +0,0 @@ -package main - -import ( - "errors" - - keycard "github.com/status-im/keycard-go" - "github.com/status-im/keycard-go/apdu" - "github.com/status-im/keycard-go/globalplatform" - "github.com/status-im/keycard-go/types" -) - -var ( - errAppletNotInstalled = errors.New("applet not installed") - errCardNotInitialized = errors.New("card not initialized") - errCardAlreadyInitialized = errors.New("card already initialized") - - ErrNotInitialized = errors.New("card not initialized") - ErrNotInstalled = errors.New("applet not initialized") -) - -// Initializer defines a struct with methods to install applets and initialize a card. -type Initializer struct { - c types.Channel -} - -// NewInitializer returns a new Initializer that communicates to Transmitter t. -func NewInitializer(t globalplatform.Transmitter) *Initializer { - return &Initializer{ - c: globalplatform.NewNormalChannel(t), - } -} - -func (i *Initializer) Init() (*keycard.Secrets, error) { - logger.Info("initialization started") - cmdSet := keycard.NewCommandSet(i.c) - - secrets, err := keycard.GenerateSecrets() - if err != nil { - return nil, err - } - - logger.Info("select keycard applet") - err = cmdSet.Select() - if err != nil { - logger.Error("select failed", "error", err) - return nil, err - } - - if !cmdSet.ApplicationInfo.Installed { - logger.Error("initialization failed", "error", errAppletNotInstalled) - return nil, errAppletNotInstalled - } - - if cmdSet.ApplicationInfo.Initialized { - logger.Error("initialization failed", "error", errCardAlreadyInitialized) - return nil, errCardAlreadyInitialized - } - - logger.Info("initializing") - err = cmdSet.Init(secrets) - if err != nil { - return nil, err - } - - return secrets, nil -} - -// Info returns a types.ApplicationInfo struct with info about the card. -func (i *Initializer) Info() (*types.ApplicationInfo, error) { - logger.Info("info started") - cmdSet := keycard.NewCommandSet(i.c) - - logger.Info("select keycard applet") - err := cmdSet.Select() - if err != nil { - if e, ok := err.(*apdu.ErrBadResponse); ok && e.Sw == globalplatform.SwFileNotFound { - err = nil - } else { - logger.Error("select failed", "error", err) - } - } - - return cmdSet.ApplicationInfo, err -} - -func (i *Initializer) Pair(pairingPass string) (*types.PairingInfo, error) { - logger.Info("pairing started") - cmdSet := keycard.NewCommandSet(i.c) - - logger.Info("select keycard applet") - err := cmdSet.Select() - if err != nil { - logger.Error("select failed", "error", err) - return nil, err - } - - if !cmdSet.ApplicationInfo.Initialized { - logger.Error("pairing failed", "error", ErrNotInitialized) - return nil, ErrNotInitialized - } - - logger.Info("pairing") - err = cmdSet.Pair(pairingPass) - return cmdSet.PairingInfo, err -} - -func (i *Initializer) Status(key []byte, index int) (*types.ApplicationStatus, error) { - logger.Info("pairing started") - cmdSet := keycard.NewCommandSet(i.c) - - logger.Info("select keycard applet") - err := cmdSet.Select() - if err != nil { - logger.Error("select failed", "error", err) - return nil, err - } - - if !cmdSet.ApplicationInfo.Initialized { - logger.Error("pairing failed", "error", ErrNotInitialized) - return nil, ErrNotInitialized - } - - logger.Info("open secure channel") - cmdSet.SetPairingInfo(key, index) - err = cmdSet.OpenSecureChannel() - if err != nil { - logger.Error("open secure channel failed", "error", err) - return nil, err - } - - logger.Info("get status") - appStatus, err := cmdSet.GetStatusApplication() - if err != nil { - logger.Error("get status failed", "error", err) - return nil, err - } - - return appStatus, nil -} diff --git a/cmd/keycard/installer.go b/cmd/keycard/installer.go deleted file mode 100644 index 6e8fdb0..0000000 --- a/cmd/keycard/installer.go +++ /dev/null @@ -1,138 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "os" - "time" - - "github.com/status-im/keycard-go/apdu" - "github.com/status-im/keycard-go/globalplatform" - "github.com/status-im/keycard-go/hexutils" - "github.com/status-im/keycard-go/identifiers" - "github.com/status-im/keycard-go/types" -) - -var ( - ErrAppletAlreadyInstalled = errors.New("keycard applet already installed") - ndefRecord = hexutils.HexToBytes("0024d40f12616e64726f69642e636f6d3a706b67696d2e7374617475732e657468657265756d") -) - -// Installer defines a struct with methods to install applets in a card. -type Installer struct { - c types.Channel -} - -// NewInstaller returns a new Installer that communicates to Transmitter t. -func NewInstaller(t globalplatform.Transmitter) *Installer { - return &Installer{ - c: globalplatform.NewNormalChannel(t), - } -} - -// Install installs the applet from the specified capFile. -func (i *Installer) Install(capFile *os.File, overwriteApplet bool) error { - logger.Info("installation started") - startTime := time.Now() - cmdSet := globalplatform.NewCommandSet(i.c) - - logger.Info("check if keycard is already installed") - if err := i.checkAppletAlreadyInstalled(cmdSet, overwriteApplet); err != nil { - logger.Error("check if keycard is already installed failed", "error", err) - return err - } - - logger.Info("select ISD") - err := cmdSet.Select() - if err != nil { - logger.Error("select failed", "error", err) - return err - } - - logger.Info("opening secure channel") - if err = cmdSet.OpenSecureChannel(); err != nil { - logger.Error("open secure channel failed", "error", err) - return err - } - - logger.Info("delete old version (if present)") - if err = cmdSet.DeleteKeycardInstancesAndPackage(); err != nil { - logger.Error("delete keycard instances and package failed", "error", err) - return err - } - - logger.Info("loading package") - callback := func(index, total int) { - logger.Debug(fmt.Sprintf("loading %d/%d", index+1, total)) - } - if err = cmdSet.LoadKeycardPackage(capFile, callback); err != nil { - logger.Error("load failed", "error", err) - return err - } - - logger.Info("installing NDEF applet") - if err = cmdSet.InstallNDEFApplet(ndefRecord); err != nil { - logger.Error("installing NDEF applet failed", "error", err) - return err - } - - logger.Info("installing Keycard applet") - if err = cmdSet.InstallKeycardApplet(); err != nil { - logger.Error("installing Keycard applet failed", "error", err) - return err - } - - elapsed := time.Now().Sub(startTime) - logger.Info(fmt.Sprintf("installation completed in %f seconds", elapsed.Seconds())) - return err -} - -// Delete deletes the applet from the card. -func (i *Installer) Delete() error { - cmdSet := globalplatform.NewCommandSet(i.c) - - logger.Info("select ISD") - err := cmdSet.Select() - if err != nil { - logger.Error("select failed", "error", err) - return err - } - - logger.Info("opening secure channel") - if err = cmdSet.OpenSecureChannel(); err != nil { - logger.Error("open secure channel failed", "error", err) - return err - } - - logger.Info("delete old version") - if err = cmdSet.DeleteKeycardInstancesAndPackage(); err != nil { - logger.Error("delete keycard instances and package failed", "error", err) - return err - } - - return nil -} - -func (i *Installer) checkAppletAlreadyInstalled(cmdSet *globalplatform.CommandSet, overwriteApplet bool) error { - keycardInstanceAID, err := identifiers.KeycardInstanceAID(identifiers.KeycardDefaultInstanceIndex) - if err != nil { - return err - } - - err = cmdSet.SelectAID(keycardInstanceAID) - switch e := err.(type) { - case *apdu.ErrBadResponse: - // keycard applet not found, so not installed yet. - if e.Sw == globalplatform.SwFileNotFound { - return nil - } - return err - case nil: // selected successfully, so it's already installed - if overwriteApplet { - return nil - } - return ErrAppletAlreadyInstalled - default: - return err - } -} diff --git a/cmd/keycard/main.go b/cmd/keycard/main.go deleted file mode 100644 index aa1a57f..0000000 --- a/cmd/keycard/main.go +++ /dev/null @@ -1,288 +0,0 @@ -package main - -import ( - "bufio" - "encoding/hex" - "errors" - "flag" - "fmt" - stdlog "log" - "os" - "strconv" - "strings" - - "github.com/ebfe/scard" - "github.com/ethereum/go-ethereum/log" -) - -type commandFunc func(*scard.Card) error - -var ( - logger = log.New("package", "status-go/cmd/keycard") - - commands map[string]commandFunc - command string - - flagCapFile = flag.String("a", "", "applet cap file path") - flagOverwrite = flag.Bool("f", false, "force applet installation if already installed") - flagLogLevel = flag.String("l", "", `Log level, one of: "error", "warn", "info", "debug", and "trace"`) -) - -func initLogger() { - if *flagLogLevel == "" { - *flagLogLevel = "info" - } - - level, err := log.LvlFromString(strings.ToLower(*flagLogLevel)) - if err != nil { - stdlog.Fatal(err) - } - - handler := log.StreamHandler(os.Stderr, log.TerminalFormat(true)) - filteredHandler := log.LvlFilterHandler(level, handler) - log.Root().SetHandler(filteredHandler) -} - -func init() { - commands = map[string]commandFunc{ - "install": commandInstall, - "info": commandInfo, - "delete": commandDelete, - "init": commandInit, - "pair": commandPair, - "status": commandStatus, - "shell": commandShell, - } - - if len(os.Args) < 2 { - usage() - } - - command = os.Args[1] - if len(os.Args) > 2 { - flag.CommandLine.Parse(os.Args[2:]) - } - - initLogger() -} - -func usage() { - fmt.Printf("\nUsage:\n keycard COMMAND [FLAGS]\n\nAvailable commands:\n") - for name := range commands { - fmt.Printf(" %s\n", name) - } - fmt.Print("\nFlags:\n\n") - flag.PrintDefaults() - os.Exit(1) -} - -func fail(msg string, ctx ...interface{}) { - logger.Error(msg, ctx...) - os.Exit(1) -} - -func main() { - ctx, err := scard.EstablishContext() - if err != nil { - fail("error establishing card context", "error", err) - } - defer func() { - if err := ctx.Release(); err != nil { - logger.Error("error releasing context", "error", err) - } - }() - - readers, err := ctx.ListReaders() - if err != nil { - fail("error getting readers", "error", err) - } - - if len(readers) == 0 { - fail("couldn't find any reader") - } - - if len(readers) > 1 { - fail("too many readers found") - } - - reader := readers[0] - logger.Debug("using reader", "name", reader) - logger.Debug("connecting to card", "reader", reader) - card, err := ctx.Connect(reader, scard.ShareShared, scard.ProtocolAny) - if err != nil { - fail("error connecting to card", "error", err) - } - defer func() { - if err := card.Disconnect(scard.ResetCard); err != nil { - logger.Error("error disconnecting card", "error", err) - } - }() - - status, err := card.Status() - if err != nil { - fail("error getting card status", "error", err) - } - - switch status.ActiveProtocol { - case scard.ProtocolT0: - logger.Debug("card protocol", "T", "0") - case scard.ProtocolT1: - logger.Debug("card protocol", "T", "1") - default: - logger.Debug("card protocol", "T", "unknown") - } - - if f, ok := commands[command]; ok { - err = f(card) - if err != nil { - logger.Error("error executing command", "command", command, "error", err) - os.Exit(1) - } - os.Exit(0) - } - - fail("unknown command", "command", command) - usage() -} - -func ask(description string) string { - r := bufio.NewReader(os.Stdin) - fmt.Printf("%s: ", description) - text, err := r.ReadString('\n') - if err != nil { - stdlog.Fatal(err) - } - - return strings.TrimSpace(text) -} - -func askHex(description string) []byte { - s := ask(description) - if s[:2] == "0x" { - s = s[2:] - } - - data, err := hex.DecodeString(s) - if err != nil { - stdlog.Fatal(err) - } - - return data -} - -func askInt(description string) int { - s := ask(description) - i, err := strconv.ParseInt(s, 10, 8) - if err != nil { - stdlog.Fatal(err) - } - - return int(i) -} - -func commandInstall(card *scard.Card) error { - if *flagCapFile == "" { - logger.Error("you must specify a cap file path with the -f flag\n") - usage() - } - - f, err := os.Open(*flagCapFile) - if err != nil { - fail("error opening cap file", "error", err) - } - defer f.Close() - - i := NewInstaller(card) - - return i.Install(f, *flagOverwrite) -} - -func commandInfo(card *scard.Card) error { - i := NewInitializer(card) - info, err := i.Info() - if err != nil { - return err - } - - fmt.Printf("Installed: %+v\n", info.Installed) - fmt.Printf("Initialized: %+v\n", info.Initialized) - fmt.Printf("InstanceUID: 0x%x\n", info.InstanceUID) - fmt.Printf("SecureChannelPublicKey: 0x%x\n", info.SecureChannelPublicKey) - fmt.Printf("Version: 0x%x\n", info.Version) - fmt.Printf("AvailableSlots: 0x%x\n", info.AvailableSlots) - fmt.Printf("KeyUID: 0x%x\n", info.KeyUID) - fmt.Printf("Capabilities:\n") - fmt.Printf(" Secure channel:%v\n", info.HasSecureChannelCapability()) - fmt.Printf(" Key management:%v\n", info.HasKeyManagementCapability()) - fmt.Printf(" Credentials Management:%v\n", info.HasCredentialsManagementCapability()) - fmt.Printf(" NDEF:%v\n", info.HasNDEFCapability()) - - return nil -} - -func commandDelete(card *scard.Card) error { - i := NewInstaller(card) - err := i.Delete() - if err != nil { - return err - } - - fmt.Printf("applet deleted\n") - - return nil -} - -func commandInit(card *scard.Card) error { - i := NewInitializer(card) - secrets, err := i.Init() - if err != nil { - return err - } - - fmt.Printf("PIN %s\n", secrets.Pin()) - fmt.Printf("PUK %s\n", secrets.Puk()) - fmt.Printf("Pairing password: %s\n", secrets.PairingPass()) - - return nil -} - -func commandPair(card *scard.Card) error { - i := NewInitializer(card) - pairingPass := ask("Pairing password") - info, err := i.Pair(pairingPass) - if err != nil { - return err - } - - fmt.Printf("Pairing key 0x%x\n", info.Key) - fmt.Printf("Pairing Index %d\n", info.Index) - - return nil -} - -func commandStatus(card *scard.Card) error { - i := NewInitializer(card) - key := askHex("Pairing key") - index := askInt("Pairing index") - - appStatus, err := i.Status(key, index) - if err != nil { - return err - } - - fmt.Printf("Pin retry count: %d\n", appStatus.PinRetryCount) - fmt.Printf("PUK retry count: %d\n", appStatus.PUKRetryCount) - fmt.Printf("Key initialized: %v\n", appStatus.KeyInitialized) - - return nil -} - -func commandShell(card *scard.Card) error { - fi, _ := os.Stdin.Stat() - if (fi.Mode() & os.ModeCharDevice) == 0 { - s := NewShell(card) - return s.Run() - } else { - return errors.New("non interactive shell. you must pipe commands") - } -} diff --git a/cmd/keycard/shell.go b/cmd/keycard/shell.go deleted file mode 100644 index 6e074f7..0000000 --- a/cmd/keycard/shell.go +++ /dev/null @@ -1,485 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "encoding/hex" - "errors" - "fmt" - "io" - "os" - "regexp" - "strconv" - "strings" - - keycard "github.com/status-im/keycard-go" - "github.com/status-im/keycard-go/apdu" - "github.com/status-im/keycard-go/globalplatform" - "github.com/status-im/keycard-go/types" -) - -type shellCommand = func(args ...string) error - -type Shell struct { - t globalplatform.Transmitter - c types.Channel - secrets *keycard.Secrets - gpCmdSet *globalplatform.CommandSet - kCmdSet *keycard.CommandSet - commands map[string]shellCommand - out *bytes.Buffer -} - -func NewShell(t globalplatform.Transmitter) *Shell { - c := globalplatform.NewNormalChannel(t) - - s := &Shell{ - t: t, - c: c, - kCmdSet: keycard.NewCommandSet(c), - gpCmdSet: globalplatform.NewCommandSet(c), - out: new(bytes.Buffer), - } - - s.commands = map[string]shellCommand{ - "gp-send-apdu": s.commandGPSendAPDU, - "gp-select": s.commandGPSelect, - "gp-open-secure-channel": s.commandGPOpenSecureChannel, - "gp-delete": s.commandGPDelete, - "gp-load": s.commandGPLoad, - "gp-install-for-install": s.commandGPInstallForInstall, - "keycard-init": s.commandKeycardInit, - "keycard-select": s.commandKeycardSelect, - "keycard-pair": s.commandKeycardPair, - "keycard-open-secure-channel": s.commandKeycardOpenSecureChannel, - "keycard-get-status": s.commandKeycardGetStatus, - "keycard-set-secrets": s.commandKeycardSetSecrets, - "keycard-set-pairing": s.commandKeycardSetPairing, - "keycard-verify-pin": s.commandKeycardVerifyPIN, - "keycard-generate-key": s.commandKeycardGenerateKey, - "keycard-derive-key": s.commandKeycardDeriveKey, - "keycard-sign": s.commandKeycardSign, - "keycard-set-pinless-path": s.commandKeycardSetPinlessPath, - } - - return s -} - -func (s *Shell) write(str string) { - s.out.WriteString(str) -} - -func (s *Shell) flushOut() { - io.Copy(os.Stdout, s.out) -} - -func (s *Shell) Run() error { - reader := bufio.NewReader(os.Stdin) - defer s.flushOut() - - for { - line, err := reader.ReadString('\n') - if err != nil { - break - } - - err = s.evalLine(line) - if err != nil { - return err - } - } - - return nil -} - -func (s *Shell) commandGPSendAPDU(args ...string) error { - if err := s.requireArgs(args, 1); err != nil { - return err - } - - apdu, err := hex.DecodeString(args[0]) - if err != nil { - return err - } - - logger.Info(fmt.Sprintf("send apdu %x", apdu)) - resp, err := s.t.Transmit(apdu) - if err != nil { - logger.Error("send apdu failed", "error", err) - return err - } - logger.Info(fmt.Sprintf("raw response: %x", resp)) - - return nil -} - -func (s *Shell) commandGPSelect(args ...string) error { - if err := s.requireArgs(args, 0, 1); err != nil { - return err - } - - if len(args) == 0 { - logger.Info("select ISD") - return s.gpCmdSet.Select() - } - - aid, err := hex.DecodeString(args[0]) - if err != nil { - return err - } - - logger.Info(fmt.Sprintf("select AID %x", aid)) - return s.gpCmdSet.SelectAID(aid) -} - -func (s *Shell) commandGPOpenSecureChannel(args ...string) error { - if err := s.requireArgs(args, 0); err != nil { - return err - } - - logger.Info("open secure channel") - return s.gpCmdSet.OpenSecureChannel() -} - -func (s *Shell) commandGPDelete(args ...string) error { - if err := s.requireArgs(args, 1); err != nil { - return err - } - - aid, err := hex.DecodeString(args[0]) - if err != nil { - return err - } - - logger.Info(fmt.Sprintf("delete %x", aid)) - - return s.gpCmdSet.Delete(aid) -} - -func (s *Shell) commandGPLoad(args ...string) error { - if err := s.requireArgs(args, 2); err != nil { - return err - } - - f, err := os.Open(args[0]) - if err != nil { - return err - } - defer f.Close() - - pkgAID, err := hex.DecodeString(args[1]) - if err != nil { - return err - } - - logger.Info("load package") - callback := func(index, total int) { - logger.Debug(fmt.Sprintf("loading %d/%d", index+1, total)) - } - if err = s.gpCmdSet.LoadPackage(f, pkgAID, callback); err != nil { - logger.Error("load failed", "error", err) - return err - } - - return nil -} - -func (s *Shell) commandGPInstallForInstall(args ...string) error { - if err := s.requireArgs(args, 3, 4); err != nil { - return err - } - - pkgAID, err := hex.DecodeString(args[0]) - if err != nil { - return err - } - - appletAID, err := hex.DecodeString(args[1]) - if err != nil { - return err - } - - instanceAID, err := hex.DecodeString(args[2]) - if err != nil { - return err - } - - var params []byte - - if len(args) == 4 { - params, err = hex.DecodeString(args[3]) - if err != nil { - return err - } - } - - logger.Info("install for install", "pkg", pkgAID, "applet", appletAID, "instance", instanceAID, "params", params) - - return s.gpCmdSet.InstallForInstall(pkgAID, appletAID, instanceAID, params) -} - -func (s *Shell) commandKeycardInit(args ...string) error { - if err := s.requireArgs(args, 0); err != nil { - return err - } - - i := NewInitializer(s.t) - secrets, err := i.Init() - if err != nil { - return err - } - - s.secrets = secrets - s.write(fmt.Sprintf("PIN: %s\n", secrets.Pin())) - s.write(fmt.Sprintf("PUK: %s\n", secrets.Puk())) - s.write(fmt.Sprintf("PAIRING PASSWORD: %s\n", secrets.PairingPass())) - - return nil -} - -func (s *Shell) commandKeycardSetSecrets(args ...string) error { - if err := s.requireArgs(args, 3); err != nil { - return err - } - - s.secrets = keycard.NewSecrets(args[0], args[1], args[2]) - - return nil -} - -func (s *Shell) commandKeycardSelect(args ...string) error { - if err := s.requireArgs(args, 0); err != nil { - return err - } - - logger.Info("select keycard") - err := s.kCmdSet.Select() - info := s.kCmdSet.ApplicationInfo - - s.write(fmt.Sprintf("Installed: %+v\n", info.Installed)) - s.write(fmt.Sprintf("Initialized: %+v\n", info.Initialized)) - s.write(fmt.Sprintf("InstanceUID: %x\n", info.InstanceUID)) - s.write(fmt.Sprintf("SecureChannelPublicKey: %x\n", info.SecureChannelPublicKey)) - s.write(fmt.Sprintf("Version: %x\n", info.Version)) - s.write(fmt.Sprintf("AvailableSlots: %x\n", info.AvailableSlots)) - s.write(fmt.Sprintf("KeyUID: %x\n", info.KeyUID)) - s.write(fmt.Sprintf("Capabilities:\n")) - s.write(fmt.Sprintf(" Secure channel:%v\n", info.HasSecureChannelCapability())) - s.write(fmt.Sprintf(" Key management:%v\n", info.HasKeyManagementCapability())) - s.write(fmt.Sprintf(" Credentials Management:%v\n", info.HasCredentialsManagementCapability())) - s.write(fmt.Sprintf(" NDEF:%v\n", info.HasNDEFCapability())) - - if e, ok := err.(*apdu.ErrBadResponse); ok && e.Sw == globalplatform.SwFileNotFound { - logger.Error("select keycard failed", "error", err) - return ErrNotInstalled - } - - return err -} - -func (s *Shell) commandKeycardPair(args ...string) error { - if err := s.requireArgs(args, 0); err != nil { - return err - } - - if s.secrets == nil { - return errors.New("cannot pair without setting secrets") - } - - err := s.kCmdSet.Pair(s.secrets.PairingPass()) - if err != nil { - return err - } - - s.write(fmt.Sprintf("PAIRING KEY: %x\n", s.kCmdSet.PairingInfo.Key)) - s.write(fmt.Sprintf("PAIRING INDEX: %v\n", s.kCmdSet.PairingInfo.Index)) - - return nil -} - -func (s *Shell) commandKeycardSetPairing(args ...string) error { - if err := s.requireArgs(args, 2); err != nil { - return err - } - - key, err := s.parseHex(args[0]) - if err != nil { - return err - } - - index, err := strconv.ParseInt(args[1], 10, 8) - if err != nil { - return err - } - - s.kCmdSet.SetPairingInfo(key, int(index)) - - return nil -} - -func (s *Shell) commandKeycardOpenSecureChannel(args ...string) error { - if err := s.requireArgs(args, 0); err != nil { - return err - } - - if s.kCmdSet.PairingInfo == nil { - return errors.New("cannot open secure channel without setting pairing info") - } - - logger.Info("open keycard secure channel") - if err := s.kCmdSet.OpenSecureChannel(); err != nil { - logger.Error("open keycard secure channel failed", "error", err) - return err - } - - return nil -} - -func (s *Shell) commandKeycardGetStatus(args ...string) error { - if err := s.requireArgs(args, 0); err != nil { - return err - } - - logger.Info("get status application") - appStatus, err := s.kCmdSet.GetStatusApplication() - if err != nil { - logger.Error("get status application failed", "error", err) - return err - } - - logger.Info("get status key path") - keyStatus, err := s.kCmdSet.GetStatusKeyPath() - if err != nil { - logger.Error("get status key path failed", "error", err) - return err - } - - s.write(fmt.Sprintf("STATUS - PIN RETRY COUNT: %d\n", appStatus.PinRetryCount)) - s.write(fmt.Sprintf("STATUS - PUK RETRY COUNT: %d\n", appStatus.PUKRetryCount)) - s.write(fmt.Sprintf("STATUS - KEY INITIALIZED: %v\n", appStatus.KeyInitialized)) - s.write(fmt.Sprintf("STATUS - KEY PATH: %v\n", keyStatus.Path)) - - return nil -} - -func (s *Shell) commandKeycardVerifyPIN(args ...string) error { - if err := s.requireArgs(args, 1); err != nil { - return err - } - - logger.Info("verify PIN") - if err := s.kCmdSet.VerifyPIN(args[0]); err != nil { - logger.Error("verify PIN failed", "error", err) - return err - } - - return nil -} - -func (s *Shell) commandKeycardGenerateKey(args ...string) error { - if err := s.requireArgs(args, 0); err != nil { - return err - } - - logger.Info("generate key") - keyUID, err := s.kCmdSet.GenerateKey() - if err != nil { - return err - } - - s.write(fmt.Sprintf("KEY UID %x\n", keyUID)) - - return nil -} - -func (s *Shell) commandKeycardDeriveKey(args ...string) error { - if err := s.requireArgs(args, 1); err != nil { - return err - } - - logger.Info(fmt.Sprintf("derive key %s", args[0])) - if err := s.kCmdSet.DeriveKey(args[0]); err != nil { - logger.Error("derive key failed", "error", err) - return err - } - - return nil -} - -func (s *Shell) commandKeycardSign(args ...string) error { - if err := s.requireArgs(args, 1); err != nil { - return err - } - - data, err := s.parseHex(args[0]) - if err != nil { - logger.Error("failed parsing hex data", "error", err) - return err - } - - logger.Info("sign") - sig, err := s.kCmdSet.Sign(data) - if err != nil { - logger.Error("sign failed", "error", err) - return err - } - - s.write(fmt.Sprintf("SIGNATURE R: %x\n", sig.R())) - s.write(fmt.Sprintf("SIGNATURE S: %x\n", sig.S())) - s.write(fmt.Sprintf("SIGNATURE V: %x\n", sig.V())) - - return nil -} - -func (s *Shell) commandKeycardSetPinlessPath(args ...string) error { - if err := s.requireArgs(args, 1); err != nil { - return err - } - - logger.Info(fmt.Sprintf("set pinless path %s", args[0])) - if err := s.kCmdSet.SetPinlessPath(args[0]); err != nil { - logger.Error("set pinless path failed", "error", err) - return err - } - - return nil -} - -func (s *Shell) requireArgs(args []string, possibleArgsN ...int) error { - for _, n := range possibleArgsN { - if len(args) == n { - return nil - } - } - - ns := make([]string, len(possibleArgsN)) - for i, n := range possibleArgsN { - ns[i] = fmt.Sprintf("%d", n) - } - - return fmt.Errorf("wrong number of argument. got: %d, expected: %v", len(args), strings.Join(ns, " | ")) -} - -func (s *Shell) evalLine(rawLine string) error { - line := strings.TrimSpace(rawLine) - - if len(line) == 0 || strings.HasPrefix(line, "#") { - return nil - } - - reg := regexp.MustCompile("\\s+") - parts := reg.Split(line, -1) - if cmd, ok := s.commands[parts[0]]; ok { - return cmd(parts[1:]...) - } - - return fmt.Errorf("command not found: %s", parts[0]) -} - -func (s *Shell) parseHex(str string) ([]byte, error) { - if str[:2] == "0x" { - str = str[2:] - } - - return hex.DecodeString(str) -}