2025-01-10 12:13:43 +00:00
|
|
|
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"
|
2025-01-20 11:45:31 +01:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
"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
|
|
|
)
|
|
|
|
|
2025-01-10 12:13:43 +00: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()
|
2025-01-10 12:13:43 +00:00
|
|
|
} 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
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00: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)
|
2025-01-10 12:13:43 +00:00
|
|
|
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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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))
|
2025-01-10 12:13:43 +00:00
|
|
|
} 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)
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
err = f.pauseAndWait(EnterPairing, internal.ErrorPairing)
|
2021-10-20 12:01:38 +03:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return f.pair(kc)
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) initCard(kc *internal.KeycardContext) error {
|
2021-10-22 09:55:00 +03:00
|
|
|
newPIN, pinOK := f.params[NewPIN]
|
|
|
|
|
|
|
|
if !pinOK {
|
2025-01-10 12:13:43 +00:00
|
|
|
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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
err := kc.Init(newPIN.(string), newPUK.(string), newPairing.(string))
|
2021-10-22 09:55:00 +03:00
|
|
|
|
2025-01-10 12:13:43 +00: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
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
|
2025-01-10 12:13:43 +00: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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
pairing = f.pairings.Get(f.cardInfo.instanceUID)
|
2021-10-20 12:01:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if pairing != nil {
|
2025-01-10 12:13:43 +00:00
|
|
|
err := kc.OpenSecureChannel(pairing.Index, pairing.Key)
|
2021-10-20 12:01:38 +03:00
|
|
|
|
|
|
|
if err == nil {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
2025-01-10 12:13:43 +00:00
|
|
|
} else if internal.IsSCardError(err) {
|
2021-10-20 12:01:38 +03:00
|
|
|
return restartErr()
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00: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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
2025-01-10 12:13:43 +00:00
|
|
|
} else if internal.IsSCardError(err) {
|
2021-10-21 10:41:20 +03:00
|
|
|
return restartErr()
|
2025-01-10 12:13:43 +00:00
|
|
|
} 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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00: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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
2025-01-10 12:13:43 +00:00
|
|
|
} else if internal.IsSCardError(err) {
|
2021-10-20 12:01:38 +03:00
|
|
|
return restartErr()
|
2025-01-10 12:13:43 +00:00
|
|
|
} 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)
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) unpairCurrent(kc *internal.KeycardContext) error {
|
|
|
|
err := kc.UnpairCurrent()
|
2021-10-21 08:48:51 +03:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2021-10-21 08:48:51 +03:00
|
|
|
return restartErr()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) unpair(kc *internal.KeycardContext, idx int) error {
|
|
|
|
err := kc.Unpair(uint8(idx))
|
2021-10-25 08:41:53 +03:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2021-10-25 08:41:53 +03:00
|
|
|
return restartErr()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) removeKey(kc *internal.KeycardContext) error {
|
|
|
|
err := kc.RemoveKey()
|
2021-10-25 08:41:53 +03:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2021-10-25 08:41:53 +03:00
|
|
|
return restartErr()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
return nil, errors.New(internal.ErrorNoKeys)
|
2022-08-09 08:50:39 +02:00
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else if err == io.EOF {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) storeMetadata(kc *internal.KeycardContext) error {
|
2022-08-04 11:21:23 +02:00
|
|
|
cardName, cardNameOK := f.params[CardName]
|
|
|
|
|
|
|
|
if !cardNameOK {
|
2025-01-10 12:13:43 +00:00
|
|
|
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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
err = kc.StoreMetadata(m)
|
2022-08-04 11:21:23 +02:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2022-08-04 11:21:23 +02:00
|
|
|
return restartErr()
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
|
2025-01-10 12:13:43 +00: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
|
|
|
|
2025-01-10 12:13:43 +00: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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00: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)
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) loadKeys(kc *internal.KeycardContext) error {
|
2021-10-28 09:52:39 +03:00
|
|
|
if mnemonic, ok := f.params[Mnemonic]; ok {
|
2025-01-10 12:13:43 +00:00
|
|
|
keyUID, err := kc.LoadMnemonic(mnemonic.(string), "")
|
2021-10-28 09:52:39 +03:00
|
|
|
|
2025-01-10 12:13:43 +00: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
|
|
|
|
}
|
|
|
|
|
2022-11-18 11:48:58 +01:00
|
|
|
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
|
2022-11-18 11:48:58 +01:00
|
|
|
}
|
|
|
|
} else {
|
2025-01-20 11:57:27 +01:00
|
|
|
mnemonicLength = internal.DefMnemoLen
|
2022-06-09 11:16:31 +02:00
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
indexes, err := kc.GenerateMnemonic(mnemonicLength / 3)
|
2022-06-09 11:16:31 +02:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2022-06-09 11:16:31 +02:00
|
|
|
return restartErr()
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) changePIN(kc *internal.KeycardContext) error {
|
2021-10-25 09:10:43 +03:00
|
|
|
if newPIN, ok := f.params[NewPIN]; ok {
|
2025-01-10 12:13:43 +00:00
|
|
|
err := kc.ChangePin(newPIN.(string))
|
2021-10-25 09:10:43 +03:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2021-10-25 09:10:43 +03:00
|
|
|
return restartErr()
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
err := f.pauseAndWait(EnterNewPIN, internal.ErrorChanging)
|
2021-10-25 09:10:43 +03:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return f.changePIN(kc)
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) changePUK(kc *internal.KeycardContext) error {
|
2021-10-25 09:10:43 +03:00
|
|
|
if newPUK, ok := f.params[NewPUK]; ok {
|
2025-01-10 12:13:43 +00:00
|
|
|
err := kc.ChangePuk(newPUK.(string))
|
2021-10-25 09:10:43 +03:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2021-10-25 09:10:43 +03:00
|
|
|
return restartErr()
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
err := f.pauseAndWait(EnterNewPUK, internal.ErrorChanging)
|
2021-10-25 09:10:43 +03:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return f.changePUK(kc)
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
func (f *KeycardFlow) changePairing(kc *internal.KeycardContext) error {
|
2021-10-25 09:10:43 +03:00
|
|
|
if newPairing, ok := f.params[NewPairing]; ok {
|
2025-01-10 12:13:43 +00:00
|
|
|
err := kc.ChangePairingPassword(newPairing.(string))
|
2021-10-25 09:10:43 +03:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2021-10-25 09:10:43 +03:00
|
|
|
return restartErr()
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
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
|
|
|
|
2025-01-10 12:13:43 +00: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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
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 {
|
2025-01-10 12:13:43 +00:00
|
|
|
err := f.pauseAndWait(EnterTXHash, internal.ErrorSigning)
|
2021-10-27 08:46:00 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return f.sign(kc)
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
signature, err := kc.SignWithPath(rawHash, path.(string))
|
2021-10-27 08:46:00 +03:00
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
if internal.IsSCardError(err) {
|
2021-10-27 08:46:00 +03:00
|
|
|
return nil, restartErr()
|
|
|
|
} else if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2025-01-10 12:13:43 +00:00
|
|
|
return internal.ToSignature(signature), nil
|
2021-10-27 08:46:00 +03:00
|
|
|
}
|