mirror of
https://github.com/status-im/keycard-go.git
synced 2025-02-20 15:48:16 +00:00
add get status command
This commit is contained in:
parent
91bbfbffb4
commit
a0138cd86d
@ -68,7 +68,7 @@ func (i *Initializer) Init() (*keycard.Secrets, error) {
|
||||
}
|
||||
|
||||
// Info returns a types.ApplicationInfo struct with info about the card.
|
||||
func (i *Initializer) Info() (types.ApplicationInfo, error) {
|
||||
func (i *Initializer) Info() (*types.ApplicationInfo, error) {
|
||||
logger.Info("info started")
|
||||
cmdSet := keycard.NewCommandSet(i.c)
|
||||
|
||||
@ -104,6 +104,41 @@ func (i *Initializer) Pair(pairingPass string) (*types.PairingInfo, error) {
|
||||
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")
|
||||
cmdSet.SetPairingInfo(key, index)
|
||||
appStatus, err := cmdSet.GetStatus()
|
||||
if err != nil {
|
||||
logger.Error("get status failed", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return appStatus, nil
|
||||
}
|
||||
|
||||
func (i *Initializer) initGPSecureChannel(sdaid []byte) error {
|
||||
// select card manager
|
||||
err := i.selectAID(sdaid)
|
||||
|
@ -49,7 +49,7 @@ func init() {
|
||||
"delete": commandDelete,
|
||||
"init": commandInit,
|
||||
"pair": commandPair,
|
||||
// "status": commandStatus,
|
||||
"status": commandStatus,
|
||||
}
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
@ -168,14 +168,14 @@ func askHex(description string) []byte {
|
||||
return data
|
||||
}
|
||||
|
||||
func askUint8(description string) uint8 {
|
||||
func askInt(description string) int {
|
||||
s := ask(description)
|
||||
i, err := strconv.ParseUint(s, 10, 8)
|
||||
i, err := strconv.ParseInt(s, 10, 8)
|
||||
if err != nil {
|
||||
stdlog.Fatal(err)
|
||||
}
|
||||
|
||||
return uint8(i)
|
||||
return int(i)
|
||||
}
|
||||
|
||||
func commandInstall(card *scard.Card) error {
|
||||
@ -258,20 +258,20 @@ func commandPair(card *scard.Card) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// func commandStatus(card *scard.Card) error {
|
||||
// i := NewInitializer(card)
|
||||
// index := askUint8("Pairing index")
|
||||
// key := askHex("Pairing key")
|
||||
func commandStatus(card *scard.Card) error {
|
||||
i := NewInitializer(card)
|
||||
key := askHex("Pairing key")
|
||||
index := askInt("Pairing index")
|
||||
|
||||
// appStatus, err := i.Status(index, key)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
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)
|
||||
// fmt.Printf("Public key derivation: %v\n", appStatus.PubKeyDerivation)
|
||||
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
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package keycard
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
|
||||
"github.com/status-im/keycard-go/apdu"
|
||||
"github.com/status-im/keycard-go/crypto"
|
||||
@ -14,7 +15,7 @@ import (
|
||||
type CommandSet struct {
|
||||
c types.Channel
|
||||
sc *SecureChannel
|
||||
ApplicationInfo types.ApplicationInfo
|
||||
ApplicationInfo *types.ApplicationInfo
|
||||
PairingInfo *types.PairingInfo
|
||||
}
|
||||
|
||||
@ -25,6 +26,13 @@ func NewCommandSet(c types.Channel) *CommandSet {
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *CommandSet) SetPairingInfo(key []byte, index int) {
|
||||
cs.PairingInfo = &types.PairingInfo{
|
||||
Key: key,
|
||||
Index: index,
|
||||
}
|
||||
}
|
||||
|
||||
func (cs *CommandSet) Select() error {
|
||||
instanceAID, err := identifiers.KeycardInstanceAID(identifiers.KeycardDefaultInstanceIndex)
|
||||
if err != nil {
|
||||
@ -120,6 +128,50 @@ func (cs *CommandSet) Pair(pairingPass string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *CommandSet) OpenSecureChannel() error {
|
||||
if cs.ApplicationInfo == nil {
|
||||
return errors.New("cannot open secure channel without setting PairingInfo")
|
||||
}
|
||||
|
||||
cmd := NewCommandOpenSecureChannel(uint8(cs.PairingInfo.Index), cs.sc.RawPublicKey())
|
||||
resp, err := cs.c.Send(cmd)
|
||||
if err = cs.checkOK(resp, err); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
encKey, macKey, iv := crypto.DeriveSessionKeys(cs.sc.Secret(), cs.PairingInfo.Key, resp.Data)
|
||||
cs.sc.Init(iv, encKey, macKey)
|
||||
|
||||
err = cs.mutualAuthenticate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *CommandSet) GetStatus() (*types.ApplicationStatus, error) {
|
||||
cmd := NewCommandGetStatusApplication()
|
||||
resp, err := cs.sc.Send(cmd)
|
||||
if err = cs.checkOK(resp, err); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.ParseApplicationStatus(resp.Data)
|
||||
}
|
||||
|
||||
func (cs *CommandSet) mutualAuthenticate() error {
|
||||
data := make([]byte, 32)
|
||||
if _, err := rand.Read(data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := NewCommandMutuallyAuthenticate(data)
|
||||
resp, err := cs.sc.Send(cmd)
|
||||
|
||||
return cs.checkOK(resp, err)
|
||||
}
|
||||
|
||||
func (cs *CommandSet) checkOK(resp *apdu.Response, err error, allowedResponses ...uint16) error {
|
||||
if len(allowedResponses) == 0 {
|
||||
allowedResponses = []uint16{apdu.SwOK}
|
||||
|
@ -62,8 +62,11 @@ func (a *ApplicationInfo) HasNDEFCapability() bool {
|
||||
return a.HasCapability(CapabilityNDEF)
|
||||
}
|
||||
|
||||
func ParseApplicationInfo(data []byte) (info ApplicationInfo, err error) {
|
||||
info.Installed = true
|
||||
func ParseApplicationInfo(data []byte) (*ApplicationInfo, error) {
|
||||
info := &ApplicationInfo{
|
||||
Installed: true,
|
||||
}
|
||||
|
||||
if data[0] == TagSelectResponsePreInitialized {
|
||||
info.PublicKey = data[2:]
|
||||
info.Capabilities = CapabilityCredentialsManagement
|
||||
@ -78,32 +81,32 @@ func ParseApplicationInfo(data []byte) (info ApplicationInfo, err error) {
|
||||
info.Initialized = true
|
||||
|
||||
if data[0] != TagApplicationInfoTemplate {
|
||||
return info, ErrWrongApplicationInfoTemplate
|
||||
return nil, ErrWrongApplicationInfoTemplate
|
||||
}
|
||||
|
||||
instanceUID, err := apdu.FindTag(data, TagApplicationInfoTemplate, uint8(0x8F))
|
||||
if err != nil {
|
||||
return info, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pubKey, err := apdu.FindTag(data, TagApplicationInfoTemplate, uint8(0x80))
|
||||
if err != nil {
|
||||
return info, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
appVersion, err := apdu.FindTag(data, TagApplicationInfoTemplate, uint8(0x02))
|
||||
if err != nil {
|
||||
return info, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
availableSlots, err := apdu.FindTagN(data, 1, TagApplicationInfoTemplate, uint8(0x02))
|
||||
if err != nil {
|
||||
return info, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyUID, err := apdu.FindTagN(data, 0, TagApplicationInfoTemplate, uint8(0x8E))
|
||||
if err != nil {
|
||||
return info, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
capabilities := CapabilityAll
|
||||
|
48
types/application_status.go
Normal file
48
types/application_status.go
Normal file
@ -0,0 +1,48 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/status-im/keycard-go/apdu"
|
||||
)
|
||||
|
||||
var ErrApplicationStatusTemplateNotFound = errors.New("application status template not found")
|
||||
|
||||
type ApplicationStatus struct {
|
||||
PinRetryCount int
|
||||
PUKRetryCount int
|
||||
KeyInitialized bool
|
||||
PubKeyDerivation bool
|
||||
}
|
||||
|
||||
func ParseApplicationStatus(data []byte) (*ApplicationStatus, error) {
|
||||
appStatus := &ApplicationStatus{}
|
||||
|
||||
tpl, err := apdu.FindTag(data, 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
|
||||
}
|
@ -7,13 +7,6 @@ type Channel interface {
|
||||
Send(*apdu.Command) (*apdu.Response, error)
|
||||
}
|
||||
|
||||
type ApplicationStatus struct {
|
||||
PinRetryCount int
|
||||
PUKRetryCount int
|
||||
KeyInitialized bool
|
||||
PubKeyDerivation bool
|
||||
}
|
||||
|
||||
type PairingInfo struct {
|
||||
Key []byte
|
||||
Index int
|
||||
|
Loading…
x
Reference in New Issue
Block a user