status-keycard-go/pkg/flow/commands.go

611 lines
12 KiB
Go
Raw Normal View History

package flow
2021-10-20 12:01:38 +03:00
2022-08-04 11:21:23 +02:00
import (
"errors"
2022-08-09 08:50:39 +02:00
"io"
2022-08-04 11:21:23 +02:00
"strings"
2025-01-20 11:57:27 +01:00
"github.com/status-im/keycard-go"
2022-08-09 08:50:39 +02:00
"github.com/status-im/keycard-go/apdu"
2022-08-04 11:21:23 +02:00
"github.com/status-im/keycard-go/derivationpath"
ktypes "github.com/status-im/keycard-go/types"
"github.com/status-im/status-keycard-go/internal"
2025-01-20 11:57:27 +01:00
"github.com/status-im/status-keycard-go/pkg/pairing"
"github.com/status-im/status-keycard-go/pkg/utils"
2022-08-04 11:21:23 +02:00
)
func (f *KeycardFlow) factoryReset(kc *internal.KeycardContext) error {
err := kc.FactoryReset(true)
2021-10-27 09:17:12 +03:00
if err == nil {
delete(f.params, FactoryReset)
return restartErr()
} else if internal.IsSCardError(err) {
2022-08-08 12:16:41 +02:00
return restartErr()
2021-10-27 09:17:12 +03:00
} else {
return err
}
2021-10-20 12:01:38 +03:00
}
func (f *KeycardFlow) selectKeycard(kc *internal.KeycardContext) error {
appInfo, err := kc.SelectApplet()
2021-10-20 12:01:38 +03:00
if err != nil {
return restartErr()
}
2025-01-20 11:57:27 +01:00
f.cardInfo.instanceUID = utils.Btox(appInfo.InstanceUID)
f.cardInfo.keyUID = utils.Btox(appInfo.KeyUID)
f.cardInfo.freeSlots = internal.BytesToInt(appInfo.AvailableSlots)
2024-11-29 16:04:29 +09:00
f.cardInfo.version = internal.BytesToInt(appInfo.Version)
2022-08-08 12:16:41 +02:00
2021-10-20 12:01:38 +03:00
if !appInfo.Installed {
return f.pauseAndRestart(SwapCard, internal.ErrorNotAKeycard)
2021-10-20 12:01:38 +03:00
}
if requiredInstanceUID, ok := f.params[InstanceUID]; ok {
if f.cardInfo.instanceUID != requiredInstanceUID {
return f.pauseAndRestart(SwapCard, InstanceUID)
}
}
if requiredKeyUID, ok := f.params[KeyUID]; ok {
if f.cardInfo.keyUID != requiredKeyUID {
return f.pauseAndRestart(SwapCard, KeyUID)
}
}
return nil
}
func (f *KeycardFlow) pair(kc *internal.KeycardContext) error {
2021-10-20 12:01:38 +03:00
if f.cardInfo.freeSlots == 0 {
return f.pauseAndRestart(SwapCard, FreeSlots)
}
2022-02-07 16:19:32 +01:00
pairingPass, ok := f.params[PairingPass]
2021-10-20 12:01:38 +03:00
2022-02-07 16:19:32 +01:00
if !ok {
2025-01-20 11:57:27 +01:00
pairingPass = internal.DefPairing
2022-02-07 16:19:32 +01:00
}
2025-01-20 11:57:27 +01:00
pair, err := kc.Pair(pairingPass.(string))
2021-10-20 12:01:38 +03:00
2022-02-07 16:19:32 +01:00
if err == nil {
2025-01-20 11:57:27 +01:00
return f.pairings.Store(f.cardInfo.instanceUID, pairing.ToPairInfo(pair))
} else if internal.IsSCardError(err) {
2022-02-07 16:19:32 +01:00
return restartErr()
2021-10-20 12:01:38 +03:00
}
2022-02-07 16:19:32 +01:00
delete(f.params, PairingPass)
err = f.pauseAndWait(EnterPairing, internal.ErrorPairing)
2021-10-20 12:01:38 +03:00
if err != nil {
return err
}
return f.pair(kc)
}
func (f *KeycardFlow) initCard(kc *internal.KeycardContext) error {
2021-10-22 09:55:00 +03:00
newPIN, pinOK := f.params[NewPIN]
if !pinOK {
err := f.pauseAndWait(EnterNewPIN, internal.ErrorRequireInit)
2021-10-22 11:49:55 +03:00
if err != nil {
return err
}
2021-10-22 09:55:00 +03:00
return f.initCard(kc)
}
newPUK, pukOK := f.params[NewPUK]
if !pukOK {
err := f.pauseAndWait(EnterNewPUK, internal.ErrorRequireInit)
2021-10-22 11:49:55 +03:00
if err != nil {
return err
}
2021-10-22 09:55:00 +03:00
return f.initCard(kc)
}
newPairing, pairingOK := f.params[NewPairing]
if !pairingOK {
2025-01-20 11:57:27 +01:00
newPairing = internal.DefPairing
2021-10-22 09:55:00 +03:00
}
err := kc.Init(newPIN.(string), newPUK.(string), newPairing.(string))
2021-10-22 09:55:00 +03:00
if internal.IsSCardError(err) {
2022-08-08 12:16:41 +02:00
return restartErr()
} else if err != nil {
2021-10-28 09:52:39 +03:00
return err
2021-10-22 09:55:00 +03:00
}
2021-10-28 09:52:39 +03:00
f.params[PIN] = newPIN
f.params[PairingPass] = newPairing
delete(f.params, NewPIN)
delete(f.params, NewPUK)
delete(f.params, NewPairing)
return restartErr()
2021-10-20 12:01:38 +03:00
}
2024-12-03 12:27:37 +09:00
func (f *KeycardFlow) verifyAuthenticity(kc *internal.KeycardContext) error {
if (len(f.knownCA) == 0) || (f.cardInfo.instanceUID == f.params[SkipAuthUID]) {
return nil
}
ca, err := kc.Identify()
if (err != nil) || !internal.ContainsString(ca, f.knownCA) {
return authenticityErr()
}
return nil
}
func (f *KeycardFlow) openSC(kc *internal.KeycardContext, giveup bool) error {
2025-01-20 11:57:27 +01:00
var pairing *pairing.Info
2021-10-22 09:32:07 +03:00
if !kc.ApplicationInfo().Initialized && !giveup {
2021-10-20 12:01:38 +03:00
return f.initCard(kc)
2021-10-22 09:32:07 +03:00
} else {
pairing = f.pairings.Get(f.cardInfo.instanceUID)
2021-10-20 12:01:38 +03:00
}
if pairing != nil {
err := kc.OpenSecureChannel(pairing.Index, pairing.Key)
2021-10-20 12:01:38 +03:00
if err == nil {
appStatus, err := kc.GetStatusApplication()
2021-10-20 12:01:38 +03:00
if err != nil {
// getStatus can only fail for connection errors
return restartErr()
}
f.cardInfo.pinRetries = appStatus.PinRetryCount
f.cardInfo.pukRetries = appStatus.PUKRetryCount
return nil
} else if internal.IsSCardError(err) {
2021-10-20 12:01:38 +03:00
return restartErr()
}
f.pairings.Delete(f.cardInfo.instanceUID)
2021-10-20 12:01:38 +03:00
}
2024-12-03 12:27:37 +09:00
err := f.verifyAuthenticity(kc)
if err != nil {
return err
}
2021-10-22 09:32:07 +03:00
if giveup {
return giveupErr()
}
2024-12-03 12:27:37 +09:00
err = f.pair(kc)
2021-10-20 12:01:38 +03:00
if err != nil {
return err
}
2021-10-22 09:32:07 +03:00
return f.openSC(kc, giveup)
2021-10-20 12:01:38 +03:00
}
func (f *KeycardFlow) unblockPIN(kc *internal.KeycardContext) error {
2022-07-29 12:08:46 +02:00
if f.cardInfo.pukRetries == 0 {
return f.pauseAndRestart(SwapCard, PUKRetries)
}
2021-10-21 10:41:20 +03:00
pukError := ""
var err error
newPIN, pinOK := f.params[NewPIN]
puk, pukOK := f.params[PUK]
if pinOK && pukOK {
err = kc.UnblockPIN(puk.(string), newPIN.(string))
2021-10-21 10:41:20 +03:00
if err == nil {
2025-01-20 11:57:27 +01:00
f.cardInfo.pinRetries = internal.MaxPINRetries
f.cardInfo.pukRetries = internal.MaxPUKRetries
2021-10-21 10:41:20 +03:00
f.params[PIN] = newPIN
delete(f.params, NewPIN)
delete(f.params, PUK)
return nil
} else if internal.IsSCardError(err) {
2021-10-21 10:41:20 +03:00
return restartErr()
} else if leftRetries, ok := internal.GetRetries(err); ok {
2021-10-21 10:41:20 +03:00
f.cardInfo.pukRetries = leftRetries
delete(f.params, PUK)
pukOK = false
}
pukError = PUK
}
2022-07-29 12:08:46 +02:00
if f.cardInfo.pukRetries == 0 {
return f.pauseAndRestart(SwapCard, PUKRetries)
}
2021-10-21 10:41:20 +03:00
if !pukOK {
err = f.pauseAndWait(EnterPUK, pukError)
} else if !pinOK {
err = f.pauseAndWait(EnterNewPIN, internal.ErrorUnblocking)
2021-10-21 10:41:20 +03:00
}
if err != nil {
return err
}
2021-10-21 14:17:55 +03:00
return f.unblockPIN(kc)
2021-10-20 12:01:38 +03:00
}
func (f *KeycardFlow) authenticate(kc *internal.KeycardContext) error {
2022-07-29 12:08:46 +02:00
if f.cardInfo.pinRetries == 0 {
2021-10-22 12:57:53 +03:00
// succesful unblock leaves the card authenticated
2021-10-21 14:17:55 +03:00
return f.unblockPIN(kc)
2021-10-20 12:01:38 +03:00
}
pinError := ""
if pin, ok := f.params[PIN]; ok {
err := kc.VerifyPin(pin.(string))
2021-10-20 12:01:38 +03:00
if err == nil {
2025-01-20 11:57:27 +01:00
f.cardInfo.pinRetries = internal.MaxPINRetries
2021-10-20 12:01:38 +03:00
return nil
} else if internal.IsSCardError(err) {
2021-10-20 12:01:38 +03:00
return restartErr()
} else if leftRetries, ok := internal.GetRetries(err); ok {
2021-10-20 12:01:38 +03:00
f.cardInfo.pinRetries = leftRetries
2021-10-21 10:41:20 +03:00
delete(f.params, PIN)
2021-10-20 12:01:38 +03:00
}
pinError = PIN
}
2022-07-29 10:33:53 +02:00
if f.cardInfo.pinRetries == 0 {
return f.unblockPIN(kc)
}
2021-10-20 12:01:38 +03:00
err := f.pauseAndWait(EnterPIN, pinError)
if err != nil {
return err
}
return f.authenticate(kc)
}
func (f *KeycardFlow) openSCAndAuthenticate(kc *internal.KeycardContext, giveup bool) error {
2021-10-22 09:32:07 +03:00
err := f.openSC(kc, giveup)
2021-10-20 12:01:38 +03:00
if err != nil {
return err
}
return f.authenticate(kc)
}
2021-10-21 08:48:51 +03:00
func (f *KeycardFlow) unpairCurrent(kc *internal.KeycardContext) error {
err := kc.UnpairCurrent()
2021-10-21 08:48:51 +03:00
if internal.IsSCardError(err) {
2021-10-21 08:48:51 +03:00
return restartErr()
}
return err
}
func (f *KeycardFlow) unpair(kc *internal.KeycardContext, idx int) error {
err := kc.Unpair(uint8(idx))
2021-10-25 08:41:53 +03:00
if internal.IsSCardError(err) {
2021-10-25 08:41:53 +03:00
return restartErr()
}
return err
}
func (f *KeycardFlow) removeKey(kc *internal.KeycardContext) error {
err := kc.RemoveKey()
2021-10-25 08:41:53 +03:00
if internal.IsSCardError(err) {
2021-10-25 08:41:53 +03:00
return restartErr()
}
return err
}
func (f *KeycardFlow) getMetadata(kc *internal.KeycardContext) (*internal.Metadata, error) {
m, err := kc.GetMetadata()
2022-08-04 11:21:23 +02:00
2022-08-09 08:50:39 +02:00
if err == nil {
return internal.ToMetadata(m), nil
} else if internal.IsSCardError(err) {
2022-08-04 11:21:23 +02:00
return nil, restartErr()
2022-08-09 08:50:39 +02:00
} else if serr, ok := err.(*apdu.ErrBadResponse); ok {
if serr.Sw == 0x6d00 {
return nil, errors.New(internal.ErrorNoKeys)
2022-08-09 08:50:39 +02:00
} else {
return nil, err
}
} else if err == io.EOF {
return nil, errors.New(internal.ErrorNoData)
2022-08-09 08:50:39 +02:00
} else {
2022-08-04 11:21:23 +02:00
return nil, err
}
}
func (f *KeycardFlow) storeMetadata(kc *internal.KeycardContext) error {
2022-08-04 11:21:23 +02:00
cardName, cardNameOK := f.params[CardName]
if !cardNameOK {
err := f.pauseAndWait(EnterName, internal.ErrorStoreMeta)
2022-08-04 11:21:23 +02:00
if err != nil {
return err
}
return f.storeMetadata(kc)
}
w, walletsOK := f.params[WalletPaths]
if !walletsOK {
err := f.pauseAndWait(EnterWallets, internal.ErrorStoreMeta)
2022-08-04 11:21:23 +02:00
if err != nil {
return err
}
return f.storeMetadata(kc)
}
2022-08-18 16:49:41 +02:00
wallets := w.([]interface{})
2022-08-04 11:21:23 +02:00
paths := make([]uint32, len(wallets))
for i, p := range wallets {
2025-01-20 11:57:27 +01:00
if !strings.HasPrefix(p.(string), internal.WalletRoothPath) {
return errors.New("path must start with " + internal.WalletRoothPath)
2022-08-04 11:21:23 +02:00
}
2022-08-18 16:49:41 +02:00
_, components, err := derivationpath.Decode(p.(string))
2022-08-04 11:21:23 +02:00
if err != nil {
return err
}
paths[i] = components[len(components)-1]
}
m, err := ktypes.NewMetadata(cardName.(string), paths)
if err != nil {
return err
}
err = kc.StoreMetadata(m)
2022-08-04 11:21:23 +02:00
if internal.IsSCardError(err) {
2022-08-04 11:21:23 +02:00
return restartErr()
}
return err
}
func (f *KeycardFlow) exportKey(kc *internal.KeycardContext, path string, onlyPublic bool) (*internal.KeyPair, error) {
2024-11-29 16:04:29 +09:00
var p2 uint8
if onlyPublic {
p2 = keycard.P2ExportKeyPublicOnly
} else {
p2 = keycard.P2ExportKeyPrivateAndPublic
}
return f.exportKeyExtended(kc, path, p2)
}
func (f *KeycardFlow) exportKeyExtended(kc *internal.KeycardContext, path string, p2 uint8) (*internal.KeyPair, error) {
2025-01-20 11:57:27 +01:00
keyPair, err := kc.ExportKey(true, path == internal.MasterPath, p2, path)
2021-10-21 08:48:51 +03:00
if internal.IsSCardError(err) {
2021-10-21 08:48:51 +03:00
return nil, restartErr()
}
return keyPair, err
}
2021-10-25 09:10:43 +03:00
func (f *KeycardFlow) exportBIP44Key(kc *internal.KeycardContext) (interface{}, error) {
2021-10-28 09:52:39 +03:00
if path, ok := f.params[BIP44Path]; ok {
2022-12-22 10:00:34 +01:00
exportPrivParam, ok := f.params[ExportPriv]
exportPrivate := (!ok || !exportPrivParam.(bool))
if pathStr, ok := path.(string); ok {
return f.exportKey(kc, pathStr, exportPrivate)
} else if paths, ok := path.([]interface{}); ok {
keys := make([]*internal.KeyPair, len(paths))
2022-12-22 10:00:34 +01:00
for i, path := range paths {
key, err := f.exportKey(kc, path.(string), exportPrivate)
if err != nil {
return nil, err
}
keys[i] = key
}
return keys, nil
} else {
delete(f.params, BIP44Path)
return f.exportBIP44Key(kc)
}
2021-10-27 08:46:00 +03:00
}
err := f.pauseAndWait(EnterPath, internal.ErrorExporting)
2021-10-27 08:46:00 +03:00
if err != nil {
return nil, err
}
return f.exportBIP44Key(kc)
}
func (f *KeycardFlow) loadKeys(kc *internal.KeycardContext) error {
2021-10-28 09:52:39 +03:00
if mnemonic, ok := f.params[Mnemonic]; ok {
keyUID, err := kc.LoadMnemonic(mnemonic.(string), "")
2021-10-28 09:52:39 +03:00
if internal.IsSCardError(err) {
2021-10-28 09:52:39 +03:00
return restartErr()
} else if err != nil {
return err
}
2025-01-20 11:57:27 +01:00
f.cardInfo.keyUID = utils.Btox(keyUID)
2021-10-28 09:52:39 +03:00
return nil
}
tmpMnemonic, ok := f.params[MnemonicLen]
var mnemonicLength int
if ok {
switch t := tmpMnemonic.(type) {
case int:
mnemonicLength = t
case float64:
mnemonicLength = int(t)
default:
2025-01-20 11:57:27 +01:00
mnemonicLength = internal.DefMnemoLen
}
} else {
2025-01-20 11:57:27 +01:00
mnemonicLength = internal.DefMnemoLen
2022-06-09 11:16:31 +02:00
}
indexes, err := kc.GenerateMnemonic(mnemonicLength / 3)
2022-06-09 11:16:31 +02:00
if internal.IsSCardError(err) {
2022-06-09 11:16:31 +02:00
return restartErr()
} else if err != nil {
return err
}
err = f.pauseAndWaitWithStatus(EnterMnemonic, internal.ErrorLoading, FlowParams{MnemonicIdxs: indexes})
2021-10-28 09:52:39 +03:00
if err != nil {
return err
}
return f.loadKeys(kc)
}
func (f *KeycardFlow) changePIN(kc *internal.KeycardContext) error {
2021-10-25 09:10:43 +03:00
if newPIN, ok := f.params[NewPIN]; ok {
err := kc.ChangePin(newPIN.(string))
2021-10-25 09:10:43 +03:00
if internal.IsSCardError(err) {
2021-10-25 09:10:43 +03:00
return restartErr()
} else if err != nil {
return err
}
return nil
}
err := f.pauseAndWait(EnterNewPIN, internal.ErrorChanging)
2021-10-25 09:10:43 +03:00
if err != nil {
return err
}
return f.changePIN(kc)
}
func (f *KeycardFlow) changePUK(kc *internal.KeycardContext) error {
2021-10-25 09:10:43 +03:00
if newPUK, ok := f.params[NewPUK]; ok {
err := kc.ChangePuk(newPUK.(string))
2021-10-25 09:10:43 +03:00
if internal.IsSCardError(err) {
2021-10-25 09:10:43 +03:00
return restartErr()
} else if err != nil {
return err
}
return nil
}
err := f.pauseAndWait(EnterNewPUK, internal.ErrorChanging)
2021-10-25 09:10:43 +03:00
if err != nil {
return err
}
return f.changePUK(kc)
}
func (f *KeycardFlow) changePairing(kc *internal.KeycardContext) error {
2021-10-25 09:10:43 +03:00
if newPairing, ok := f.params[NewPairing]; ok {
err := kc.ChangePairingPassword(newPairing.(string))
2021-10-25 09:10:43 +03:00
if internal.IsSCardError(err) {
2021-10-25 09:10:43 +03:00
return restartErr()
} else if err != nil {
return err
}
return nil
}
err := f.pauseAndWait(EnterNewPair, internal.ErrorChanging)
2021-10-25 09:10:43 +03:00
if err != nil {
return err
}
return f.changePairing(kc)
}
2021-10-27 08:46:00 +03:00
func (f *KeycardFlow) sign(kc *internal.KeycardContext) (*internal.Signature, error) {
2021-10-27 08:46:00 +03:00
var err error
path, pathOK := f.params[BIP44Path]
if !pathOK {
err = f.pauseAndWait(EnterPath, internal.ErrorSigning)
2021-10-27 08:46:00 +03:00
if err != nil {
return nil, err
}
return f.sign(kc)
}
hash, hashOK := f.params[TXHash]
var rawHash []byte
if hashOK {
2025-01-20 11:57:27 +01:00
rawHash, err = utils.Xtob(hash.(string))
2021-10-27 08:46:00 +03:00
if err != nil {
hashOK = false
}
}
if !hashOK {
err := f.pauseAndWait(EnterTXHash, internal.ErrorSigning)
2021-10-27 08:46:00 +03:00
if err != nil {
return nil, err
}
return f.sign(kc)
}
signature, err := kc.SignWithPath(rawHash, path.(string))
2021-10-27 08:46:00 +03:00
if internal.IsSCardError(err) {
2021-10-27 08:46:00 +03:00
return nil, restartErr()
} else if err != nil {
return nil, err
}
return internal.ToSignature(signature), nil
2021-10-27 08:46:00 +03:00
}