keycard-go/commands.go

245 lines
4.9 KiB
Go
Raw Normal View History

2019-03-11 11:05:28 +01:00
package keycard
2018-10-22 19:33:53 +02:00
import (
2019-03-15 01:03:24 +01:00
"bytes"
"encoding/binary"
"fmt"
2019-03-01 18:44:07 +01:00
"github.com/status-im/keycard-go/apdu"
2019-03-15 01:03:24 +01:00
"github.com/status-im/keycard-go/derivationpath"
2019-03-01 18:44:07 +01:00
"github.com/status-im/keycard-go/globalplatform"
2018-10-22 19:33:53 +02:00
)
const (
2018-11-06 18:38:13 +01:00
InsInit = uint8(0xFE)
InsOpenSecureChannel = uint8(0x10)
InsMutuallyAuthenticate = uint8(0x11)
InsPair = uint8(0x12)
2019-03-27 13:05:46 +01:00
InsUnpair = uint8(0x13)
2018-11-07 14:39:58 +01:00
InsGetStatus = uint8(0xF2)
2019-03-14 16:31:30 +01:00
InsGenerateKey = uint8(0xD4)
2019-03-27 11:22:20 +01:00
InsRemoveKey = uint8(0xD3)
2019-03-14 16:31:30 +01:00
InsVerifyPIN = uint8(0x20)
2019-03-27 14:34:55 +01:00
InsChangePIN = uint8(0x21)
2019-03-15 01:03:24 +01:00
InsDeriveKey = uint8(0xD1)
InsSign = uint8(0xC0)
2019-03-16 10:03:35 +01:00
InsSetPinlessPath = uint8(0xC1)
2018-10-23 12:06:00 +02:00
2019-03-27 14:34:55 +01:00
P1PairingFirstStep = uint8(0x00)
P1PairingFinalStep = uint8(0x01)
P1GetStatusApplication = uint8(0x00)
P1GetStatusKeyPath = uint8(0x01)
P1DeriveKeyFromMaster = uint8(0x00)
P1DeriveKeyFromParent = uint8(0x01)
P1DeriveKeyFromCurrent = uint8(0x10)
P1ChangePinPIN = uint8(0x00)
P1ChangePinPUK = uint8(0x01)
P1ChangePinPairingSecret = uint8(0x02)
2019-03-27 13:05:46 +01:00
SwNoAvailablePairingSlots = 0x6A84
2018-10-22 19:33:53 +02:00
)
func NewCommandInit(data []byte) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsInit,
uint8(0x00),
uint8(0x00),
data,
)
}
2018-10-24 18:16:14 +02:00
func NewCommandPairFirstStep(challenge []byte) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsPair,
P1PairingFirstStep,
uint8(0x00),
challenge,
)
}
func NewCommandPairFinalStep(cryptogramHash []byte) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsPair,
P1PairingFinalStep,
uint8(0x00),
cryptogramHash,
)
}
2019-03-27 13:05:46 +01:00
func NewCommandUnpair(index uint8) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsUnpair,
index,
uint8(0),
[]byte{},
)
}
2018-10-24 18:16:14 +02:00
func NewCommandOpenSecureChannel(pairingIndex uint8, pubKey []byte) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsOpenSecureChannel,
pairingIndex,
uint8(0x00),
pubKey,
)
}
2018-11-06 18:38:13 +01:00
func NewCommandMutuallyAuthenticate(data []byte) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsMutuallyAuthenticate,
uint8(0x00),
uint8(0x00),
data,
)
}
2018-11-07 14:39:58 +01:00
func NewCommandGetStatus(p1 uint8) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsGetStatus,
p1,
uint8(0x00),
[]byte{},
)
}
2019-03-14 16:31:30 +01:00
func NewCommandGenerateKey() *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsGenerateKey,
uint8(0),
uint8(0),
[]byte{},
)
}
2019-03-27 11:22:20 +01:00
func NewCommandRemoveKey() *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsRemoveKey,
uint8(0),
uint8(0),
[]byte{},
)
}
2019-03-14 16:31:30 +01:00
func NewCommandVerifyPIN(pin string) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsVerifyPIN,
uint8(0),
uint8(0),
[]byte(pin),
)
}
2019-03-15 01:03:24 +01:00
2019-03-27 14:34:55 +01:00
func NewCommandChangePIN(pin string) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsChangePIN,
P1ChangePinPIN,
uint8(0),
[]byte(pin),
)
}
func NewCommandChangePUK(puk string) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsChangePIN,
P1ChangePinPUK,
uint8(0),
[]byte(puk),
)
}
func NewCommandChangePairingSecret(secret []byte) *apdu.Command {
return apdu.NewCommand(
globalplatform.ClaGp,
InsChangePIN,
P1ChangePinPairingSecret,
uint8(0),
secret,
)
}
2019-03-15 01:03:24 +01:00
func NewCommandDeriveKey(pathStr string) (*apdu.Command, error) {
2019-03-15 16:40:22 +01:00
startingPoint, path, err := derivationpath.Decode(pathStr)
2019-03-15 01:03:24 +01:00
if err != nil {
return nil, err
}
var p1 uint8
switch startingPoint {
case derivationpath.StartingPointMaster:
p1 = P1DeriveKeyFromMaster
case derivationpath.StartingPointParent:
p1 = P1DeriveKeyFromParent
case derivationpath.StartingPointCurrent:
p1 = P1DeriveKeyFromCurrent
default:
return nil, fmt.Errorf("invalid startingPoint %d", startingPoint)
}
data := new(bytes.Buffer)
for _, segment := range path {
if err := binary.Write(data, binary.BigEndian, segment); err != nil {
return nil, err
}
}
return apdu.NewCommand(
globalplatform.ClaGp,
InsDeriveKey,
p1,
uint8(0),
data.Bytes(),
), nil
}
2019-03-16 10:03:35 +01:00
func NewCommandSetPinlessPath(pathStr string) (*apdu.Command, error) {
startingPoint, path, err := derivationpath.Decode(pathStr)
if err != nil {
return nil, err
}
if startingPoint != derivationpath.StartingPointMaster {
return nil, fmt.Errorf("pinless path must be set with an absolute path")
}
data := new(bytes.Buffer)
for _, segment := range path {
if err := binary.Write(data, binary.BigEndian, segment); err != nil {
return nil, err
}
}
return apdu.NewCommand(
globalplatform.ClaGp,
InsSetPinlessPath,
uint8(0),
uint8(0),
data.Bytes(),
), nil
}
2019-03-15 01:03:24 +01:00
func NewCommandSign(data []byte) (*apdu.Command, error) {
if len(data) != 32 {
return nil, fmt.Errorf("data length must be 32, got %d", len(data))
}
return apdu.NewCommand(
globalplatform.ClaGp,
InsSign,
uint8(0),
uint8(0),
data,
), nil
}