add CommandSet and parse application info

This commit is contained in:
Andrea Franz 2019-03-11 12:24:09 +01:00
parent 077b96f9ee
commit ce5141b390
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
6 changed files with 147 additions and 14 deletions

View File

@ -61,8 +61,11 @@ 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) {
return keycard.Select(i.c, identifiers.KeycardAID)
func (i *Initializer) Info() (types.ApplicationInfo, error) {
cmdSet := keycard.NewCommandSet(i.c)
err := cmdSet.Select()
return cmdSet.ApplicationInfo, err
}
func (i *Initializer) initGPSecureChannel(sdaid []byte) error {

65
command_set.go Normal file
View File

@ -0,0 +1,65 @@
package keycard
import (
"github.com/status-im/keycard-go/apdu"
"github.com/status-im/keycard-go/globalplatform"
"github.com/status-im/keycard-go/identifiers"
"github.com/status-im/keycard-go/types"
)
type CommandSet struct {
c types.Channel
ApplicationInfo types.ApplicationInfo
}
func NewCommandSet(c types.Channel) *CommandSet {
return &CommandSet{
c: c,
}
}
func (cs *CommandSet) Select() error {
instanceAID, err := identifiers.KeycardInstanceAID(identifiers.KeycardDefaultInstanceIndex)
if err != nil {
return err
}
cmd := apdu.NewCommand(
0x00,
globalplatform.InsSelect,
uint8(0x04),
uint8(0x00),
instanceAID,
)
cmd.SetLe(0)
resp, err := cs.c.Send(cmd)
err = cs.checkOK(resp, err)
if err == nil {
appInfo, err := types.ParseApplicationInfo(resp.Data)
if err != nil {
return err
}
cs.ApplicationInfo = appInfo
return nil
}
return err
}
func (cs *CommandSet) checkOK(resp *apdu.Response, err error, allowedResponses ...uint16) error {
if len(allowedResponses) == 0 {
allowedResponses = []uint16{apdu.SwOK}
}
for _, code := range allowedResponses {
if code == resp.Sw {
return nil
}
}
return apdu.NewErrBadResponse(resp.Sw, "unexpected response")
}

View File

@ -12,6 +12,7 @@ const (
InsPair = uint8(0x12)
InsGetStatus = uint8(0xF2)
//TODO: remove
TagSelectResponsePreInitialized = uint8(0x80)
TagApplicationStatusTemplate = uint8(0xA3)
TagApplicationInfoTemplate = uint8(0xA4)

View File

@ -11,6 +11,8 @@ var (
NdefAID = []byte{0xA0, 0x00, 0x00, 0x08, 0x04, 0x00, 0x01, 0x02}
NdefInstanceAID = []byte{0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01}
KeycardDefaultInstanceIndex = 1
ErrInvalidInstanceIndex = errors.New("instance index must be between 1 and 255")
)

74
types/application_info.go Normal file
View File

@ -0,0 +1,74 @@
package types
import (
"errors"
"github.com/status-im/keycard-go/apdu"
)
var ErrWrongApplicationInfoTemplate = errors.New("wrong application info template")
const (
TagSelectResponsePreInitialized = uint8(0x80)
TagApplicationStatusTemplate = uint8(0xA3)
TagApplicationInfoTemplate = uint8(0xA4)
)
type ApplicationInfo struct {
Installed bool
Initialized bool
InstanceUID []byte
PublicKey []byte
Version []byte
AvailableSlots []byte
// KeyUID is the sha256 of of the master public key on the card.
// It's empty if the card doesn't contain any key.
KeyUID []byte
}
func ParseApplicationInfo(data []byte) (info ApplicationInfo, err error) {
info.Installed = true
if data[0] == TagSelectResponsePreInitialized {
info.PublicKey = data[2:]
return info, nil
}
info.Initialized = true
if data[0] != TagApplicationInfoTemplate {
return info, ErrWrongApplicationInfoTemplate
}
instanceUID, err := apdu.FindTag(data, TagApplicationInfoTemplate, uint8(0x8F))
if err != nil {
return info, err
}
pubKey, err := apdu.FindTag(data, TagApplicationInfoTemplate, uint8(0x80))
if err != nil {
return info, err
}
appVersion, err := apdu.FindTag(data, TagApplicationInfoTemplate, uint8(0x02))
if err != nil {
return info, err
}
availableSlots, err := apdu.FindTagN(data, 1, TagApplicationInfoTemplate, uint8(0x02))
if err != nil {
return info, err
}
keyUID, err := apdu.FindTagN(data, 0, TagApplicationInfoTemplate, uint8(0x8E))
if err != nil {
return info, err
}
info.InstanceUID = instanceUID
info.PublicKey = pubKey
info.Version = appVersion
info.AvailableSlots = availableSlots
info.KeyUID = keyUID
return info, nil
}

View File

@ -7,18 +7,6 @@ type Channel interface {
Send(*apdu.Command) (*apdu.Response, error)
}
type ApplicationInfo struct {
Installed bool
Initialized bool
InstanceUID []byte
PublicKey []byte
Version []byte
AvailableSlots []byte
// KeyUID is the sha256 of of the master public key on the card.
// It's empty if the card doesn't contain any key.
KeyUID []byte
}
type ApplicationStatus struct {
PinRetryCount int
PUKRetryCount int