From a6d70a9e6770dcb707fc7314afed768d3b1bf6fb Mon Sep 17 00:00:00 2001 From: Andrea Franz Date: Wed, 7 Nov 2018 14:39:58 +0100 Subject: [PATCH] add status command and action --- cmd/applet-installer/main.go | 12 ++++++- lightwallet/actions/actions.go | 51 +++++++++++++++++++++++++---- lightwallet/actionsets/installer.go | 12 +++---- lightwallet/commands.go | 26 +++++++++++++-- lightwallet/types.go | 7 ++++ 5 files changed, 93 insertions(+), 15 deletions(-) diff --git a/cmd/applet-installer/main.go b/cmd/applet-installer/main.go index 8cb4d37..60ddf06 100644 --- a/cmd/applet-installer/main.go +++ b/cmd/applet-installer/main.go @@ -258,5 +258,15 @@ func commandStatus(i *actionsets.Installer) error { index := askUint8("Pairing index") key := askHex("Pairing key") - return i.Status(index, key) + appStatus, err := i.Status(index, key) + 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) + fmt.Printf("Public key derivation: %v\n", appStatus.PubKeyDerivation) + + return nil } diff --git a/lightwallet/actions/actions.go b/lightwallet/actions/actions.go index f99c2b5..63fd451 100644 --- a/lightwallet/actions/actions.go +++ b/lightwallet/actions/actions.go @@ -1,6 +1,7 @@ package actions import ( + "bytes" "crypto/rand" "crypto/sha256" "errors" @@ -13,9 +14,10 @@ import ( ) var ( - ErrAlreadyInitialized = errors.New("card already initialized") - ErrNotInitialized = errors.New("card not initialized") - ErrUnknownApplicationInfoTemplate = errors.New("unknown application info template") + ErrAlreadyInitialized = errors.New("card already initialized") + ErrNotInitialized = errors.New("card not initialized") + ErrWrongApplicationInfoTemplate = errors.New("wrong application info template") + ErrApplicationStatusTemplateNotFound = errors.New("application status template not found") ) func Select(c globalplatform.Channel, aid []byte) (*lightwallet.ApplicationInfo, error) { @@ -164,13 +166,19 @@ func mutualAuthenticate(sc *lightwallet.SecureChannel) error { return checkOKResponse(err, resp) } -func Status(index uint8, key []byte) error { - return nil +func GetStatusApplication(c globalplatform.Channel) (*lightwallet.ApplicationStatus, error) { + cmd := lightwallet.NewCommandGetStatusApplication() + resp, err := c.Send(cmd) + if err = checkOKResponse(err, resp); err != nil { + return nil, err + } + + return parseApplicationStatus(resp.Data) } func parseApplicationInfo(data []byte, info *lightwallet.ApplicationInfo) (*lightwallet.ApplicationInfo, error) { if data[0] != lightwallet.TagApplicationInfoTemplate { - return nil, ErrUnknownApplicationInfoTemplate + return nil, ErrWrongApplicationInfoTemplate } instanceUID, err := apdu.FindTag(data, lightwallet.TagApplicationInfoTemplate, uint8(0x8F)) @@ -207,6 +215,37 @@ func parseApplicationInfo(data []byte, info *lightwallet.ApplicationInfo) (*ligh return info, nil } +func parseApplicationStatus(data []byte) (*lightwallet.ApplicationStatus, error) { + appStatus := &lightwallet.ApplicationStatus{} + + tpl, err := apdu.FindTag(data, lightwallet.TagApplicationStatusTemplate) + if err != nil { + return nil, ErrApplicationStatusTemplateNotFound + } + + if pinRetryCount, err := apdu.FindTag(tpl, uint8(0x02)); err == nil && len(pinRetryCount) == 1 { + appStatus.PinRetryCount = int(pinRetryCount[0]) + } + + if pukRetryCount, err := apdu.FindTagN(tpl, 1, uint8(0x02)); err == nil && len(pukRetryCount) == 1 { + appStatus.PUKRetryCount = int(pukRetryCount[0]) + } + + if keyInitialized, err := apdu.FindTag(tpl, uint8(0x01)); err == nil { + if bytes.Equal(keyInitialized, []byte{0xFF}) { + appStatus.KeyInitialized = true + } + } + + if keyDerivationSupported, err := apdu.FindTagN(tpl, 1, uint8(0x01)); err == nil { + if bytes.Equal(keyDerivationSupported, []byte{0xFF}) { + appStatus.PubKeyDerivation = true + } + } + + return appStatus, nil +} + func checkOKResponse(err error, resp *apdu.Response) error { if err != nil { return err diff --git a/lightwallet/actionsets/installer.go b/lightwallet/actionsets/installer.go index cc24c33..2f299be 100644 --- a/lightwallet/actionsets/installer.go +++ b/lightwallet/actionsets/installer.go @@ -110,26 +110,26 @@ func (i *Installer) Info() (*lightwallet.ApplicationInfo, error) { } // Status returns -func (i *Installer) Status(index uint8, key []byte) error { +func (i *Installer) Status(index uint8, key []byte) (*lightwallet.ApplicationStatus, error) { info, err := actions.Select(i.c, walletAID) if err != nil { - return err + return nil, err } if !info.Installed { - return errAppletNotInstalled + return nil, errAppletNotInstalled } if !info.Initialized { - return errCardNotInitialized + return nil, errCardNotInitialized } sc, err := actions.OpenSecureChannel(i.c, info, index, key) if err != nil { - return err + return nil, err } - return nil + return actions.GetStatusApplication(sc) } // Delete deletes the applet and related package from the card. diff --git a/lightwallet/commands.go b/lightwallet/commands.go index 03b8926..d98b697 100644 --- a/lightwallet/commands.go +++ b/lightwallet/commands.go @@ -10,12 +10,16 @@ const ( InsOpenSecureChannel = uint8(0x10) InsMutuallyAuthenticate = uint8(0x11) InsPair = uint8(0x12) + InsGetStatus = uint8(0xF2) TagSelectResponsePreInitialized = uint8(0x80) + TagApplicationStatusTemplate = uint8(0xA3) TagApplicationInfoTemplate = uint8(0xA4) - P1PairingFirstStep = uint8(0x00) - P1PairingFinalStep = uint8(0x01) + P1PairingFirstStep = uint8(0x00) + P1PairingFinalStep = uint8(0x01) + P1GetStatusApplication = uint8(0x00) + P1GetStatusKeyPath = uint8(0x01) ) func NewCommandInit(data []byte) *apdu.Command { @@ -67,3 +71,21 @@ func NewCommandMutuallyAuthenticate(data []byte) *apdu.Command { data, ) } + +func NewCommandGetStatus(p1 uint8) *apdu.Command { + return apdu.NewCommand( + globalplatform.ClaGp, + InsGetStatus, + p1, + uint8(0x00), + []byte{}, + ) +} + +func NewCommandGetStatusApplication() *apdu.Command { + return NewCommandGetStatus(P1GetStatusApplication) +} + +func NewCommandGetStatusKeyPath() *apdu.Command { + return NewCommandGetStatus(P1GetStatusKeyPath) +} diff --git a/lightwallet/types.go b/lightwallet/types.go index 5b4755f..f271b00 100644 --- a/lightwallet/types.go +++ b/lightwallet/types.go @@ -12,6 +12,13 @@ type ApplicationInfo struct { KeyUID []byte } +type ApplicationStatus struct { + PinRetryCount int + PUKRetryCount int + KeyInitialized bool + PubKeyDerivation bool +} + type PairingInfo struct { Key []byte Index int