remove cmd

This commit is contained in:
Andrea Franz 2019-03-18 19:41:15 +01:00
parent a420564d09
commit 2a3ba4fcc0
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
5 changed files with 0 additions and 1130 deletions

View File

@ -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.

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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")
}
}

View File

@ -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)
}