2018-09-14 11:30:16 +00:00
|
|
|
package apdu
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/binary"
|
2019-04-17 21:56:24 +00:00
|
|
|
"errors"
|
2018-09-14 11:30:16 +00:00
|
|
|
)
|
|
|
|
|
2019-04-17 21:56:24 +00:00
|
|
|
// ErrBadRawCommand is an error returned by ParseCommand in case the command data is not long enough.
|
|
|
|
var ErrBadRawCommand = errors.New("command must be at least 4 bytes")
|
|
|
|
|
2018-10-05 11:03:58 +00:00
|
|
|
// Command struct represent the data sent as an APDU command with CLA, Ins, P1, P2, Lc, Data, and Le.
|
2018-09-14 11:30:16 +00:00
|
|
|
type Command struct {
|
2018-09-27 16:01:09 +00:00
|
|
|
Cla uint8
|
|
|
|
Ins uint8
|
|
|
|
P1 uint8
|
|
|
|
P2 uint8
|
|
|
|
Data []byte
|
2018-09-28 09:25:08 +00:00
|
|
|
le uint8
|
2018-09-27 16:01:09 +00:00
|
|
|
requiresLe bool
|
2018-09-14 11:30:16 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 11:03:58 +00:00
|
|
|
// NewCommand returns a new apdu Command.
|
2018-09-14 11:30:16 +00:00
|
|
|
func NewCommand(cla, ins, p1, p2 uint8, data []byte) *Command {
|
|
|
|
return &Command{
|
2018-09-27 16:01:09 +00:00
|
|
|
Cla: cla,
|
|
|
|
Ins: ins,
|
|
|
|
P1: p1,
|
|
|
|
P2: p2,
|
|
|
|
Data: data,
|
|
|
|
requiresLe: false,
|
2018-09-14 11:30:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-05 11:03:58 +00:00
|
|
|
// SetLe sets the expected Le value and makes sure the Le value is sent in the apdu Command.
|
2018-09-28 09:25:08 +00:00
|
|
|
func (c *Command) SetLe(le uint8) {
|
2018-09-27 16:01:09 +00:00
|
|
|
c.requiresLe = true
|
2018-09-28 09:25:08 +00:00
|
|
|
c.le = le
|
|
|
|
}
|
|
|
|
|
2018-10-05 11:03:58 +00:00
|
|
|
// Le returns if Le is set and its value.
|
2018-09-28 09:25:08 +00:00
|
|
|
func (c *Command) Le() (bool, uint8) {
|
|
|
|
return c.requiresLe, c.le
|
2018-09-27 16:01:09 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 11:03:58 +00:00
|
|
|
// Serialize serielizes the command into a raw bytes sequence.
|
2018-09-19 13:29:43 +00:00
|
|
|
func (c *Command) Serialize() ([]byte, error) {
|
2018-09-14 11:30:16 +00:00
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
|
|
|
if err := binary.Write(buf, binary.BigEndian, c.Cla); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(buf, binary.BigEndian, c.Ins); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(buf, binary.BigEndian, c.P1); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Write(buf, binary.BigEndian, c.P2); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(c.Data) > 0 {
|
|
|
|
if err := binary.Write(buf, binary.BigEndian, uint8(len(c.Data))); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := binary.Write(buf, binary.BigEndian, c.Data); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-27 16:01:09 +00:00
|
|
|
if c.requiresLe {
|
2018-09-28 09:25:08 +00:00
|
|
|
if err := binary.Write(buf, binary.BigEndian, c.le); err != nil {
|
2018-09-27 16:01:09 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2018-09-14 11:30:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return buf.Bytes(), nil
|
|
|
|
}
|
2019-04-17 21:56:24 +00:00
|
|
|
|
|
|
|
func (c *Command) deserialize(data []byte) error {
|
|
|
|
if len(data) < 4 {
|
|
|
|
return ErrBadRawCommand
|
|
|
|
}
|
|
|
|
|
|
|
|
buf := bytes.NewReader(data)
|
|
|
|
|
|
|
|
if err := binary.Read(buf, binary.BigEndian, &c.Cla); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Read(buf, binary.BigEndian, &c.Ins); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Read(buf, binary.BigEndian, &c.P1); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := binary.Read(buf, binary.BigEndian, &c.P2); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var lc uint8
|
|
|
|
if err := binary.Read(buf, binary.BigEndian, &lc); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
cmdData := make([]byte, lc)
|
|
|
|
if err := binary.Read(buf, binary.BigEndian, &cmdData); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
c.Data = cmdData
|
|
|
|
|
|
|
|
var le uint8
|
|
|
|
if err := binary.Read(buf, binary.BigEndian, &le); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
c.SetLe(le)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseCommand parses a raw command and returns a Command
|
|
|
|
func ParseCommand(raw []byte) (*Command, error) {
|
|
|
|
cmd := &Command{}
|
|
|
|
return cmd, cmd.deserialize(raw)
|
|
|
|
}
|