diff --git a/cash_command_set.go b/cash_command_set.go new file mode 100644 index 0000000..5952051 --- /dev/null +++ b/cash_command_set.go @@ -0,0 +1,70 @@ +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 CashCommandSet struct { + c types.Channel + CashApplicationInfo *types.CashApplicationInfo +} + +func NewCashCommandSet(c types.Channel) *CashCommandSet { + return &CashCommandSet{ + c: c, + } +} + +func (cs *CashCommandSet) Select() error { + cmd := globalplatform.NewCommandSelect(identifiers.CashInstanceAID) + cmd.SetLe(0) + resp, err := cs.c.Send(cmd) + if err = cs.checkOK(resp, err); err != nil { + cs.CashApplicationInfo = &types.CashApplicationInfo{} + return err + } + + appInfo, err := types.ParseCashApplicationInfo(resp.Data) + if err != nil { + return err + } + + cs.CashApplicationInfo = appInfo + + return nil +} + +func (cs *CashCommandSet) Sign(data []byte) (*types.Signature, error) { + cmd, err := NewCommandSign(data, 0x00, "") + if err != nil { + return nil, err + } + + resp, err := cs.c.Send(cmd) + if err = cs.checkOK(resp, err); err != nil { + return nil, err + } + + return types.ParseSignature(data, resp.Data) +} + +func (cs *CashCommandSet) checkOK(resp *apdu.Response, err error, allowedResponses ...uint16) error { + if err != nil { + return err + } + + 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") +} diff --git a/types/cash_application_info.go b/types/cash_application_info.go new file mode 100644 index 0000000..a63c1f5 --- /dev/null +++ b/types/cash_application_info.go @@ -0,0 +1,38 @@ +package types + +import "github.com/status-im/keycard-go/apdu" + +type CashApplicationInfo struct { + PublicKey []byte + PublicKeyData []byte + Version []byte +} + +func ParseCashApplicationInfo(data []byte) (*CashApplicationInfo, error) { + info := &CashApplicationInfo{} + + if data[0] != TagApplicationInfoTemplate { + return nil, ErrWrongApplicationInfoTemplate + } + + pubKey, err := apdu.FindTag(data, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x80}) + if err != nil { + return nil, err + } + + pubKeyData, err := apdu.FindTag(data, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x82}) + if err != nil { + return nil, err + } + + appVersion, err := apdu.FindTag(data, apdu.Tag{TagApplicationInfoTemplate}, apdu.Tag{0x02}) + if err != nil { + return nil, err + } + + info.PublicKey = pubKey + info.PublicKeyData = pubKeyData + info.Version = appVersion + + return info, nil +}