split commands from flows

This commit is contained in:
Michele Balistreri 2021-10-20 12:01:38 +03:00
parent 7829094f92
commit 2b84b6560a
No known key found for this signature in database
GPG Key ID: E9567DA33A4F791A
3 changed files with 192 additions and 172 deletions

View File

@ -92,4 +92,5 @@ func main() {
testFlow(skg.GetAppInfo, skg.FlowParams{})
testFlow(skg.RecoverAccount, skg.FlowParams{skg.PIN: "234567"})
testFlow(skg.UnpairThis, skg.FlowParams{skg.PIN: correctPIN})
}

206
flow.go
View File

@ -104,38 +104,6 @@ func (f *KeycardFlow) runFlow() {
f.state = Idle
}
func (f *KeycardFlow) connectedFlow() (FlowStatus, error) {
kc := f.connect()
defer f.closeKeycard(kc)
if kc == nil {
return nil, errors.New(ErrorConnection)
}
if factoryReset, ok := f.params[FactoryReset]; ok && factoryReset.(bool) {
err := f.factoryReset(kc)
if err != nil {
return nil, err
}
}
err := f.selectKeycard(kc)
if err != nil {
return nil, err
}
switch f.flowType {
case GetAppInfo:
return f.getAppInfoFlow(kc)
case RecoverAccount:
return f.recoverAccountFlow(kc)
default:
return nil, errors.New(ErrorUnknownFlow)
}
}
func (f *KeycardFlow) pause(action string, errMsg string) {
status := FlowParams{}
@ -159,6 +127,10 @@ func (f *KeycardFlow) pause(action string, errMsg string) {
}
func (f *KeycardFlow) pauseAndWait(action string, errMsg string) error {
if f.state == Cancelling {
return errors.New("cancel")
}
f.pause(action, errMsg)
<-f.wakeUp
@ -210,158 +182,38 @@ func (f *KeycardFlow) connect() *keycardContext {
}
}
func (f *KeycardFlow) factoryReset(kc *keycardContext) error {
// on success, remove the FactoryReset switch to avoid re-triggering it
// if card is disconnected/reconnected
delete(f.params, FactoryReset)
return errors.New("not implemented")
}
func (f *KeycardFlow) connectedFlow() (FlowStatus, error) {
kc := f.connect()
defer f.closeKeycard(kc)
func (f *KeycardFlow) selectKeycard(kc *keycardContext) error {
appInfo, err := kc.selectApplet()
f.cardInfo.instanceUID = tox(appInfo.InstanceUID)
f.cardInfo.keyUID = tox(appInfo.KeyUID)
f.cardInfo.freeSlots = bytesToInt(appInfo.AvailableSlots)
if err != nil {
return restartErr()
if kc == nil {
return nil, errors.New(ErrorConnection)
}
if !appInfo.Installed {
return f.pauseAndRestart(SwapCard, ErrorNotAKeycard)
}
if factoryReset, ok := f.params[FactoryReset]; ok && factoryReset.(bool) {
err := f.factoryReset(kc)
if requiredInstanceUID, ok := f.params[InstanceUID]; ok {
if f.cardInfo.instanceUID != requiredInstanceUID {
return f.pauseAndRestart(SwapCard, InstanceUID)
if err != nil {
return nil, err
}
}
if requiredKeyUID, ok := f.params[KeyUID]; ok {
if f.cardInfo.keyUID != requiredKeyUID {
return f.pauseAndRestart(SwapCard, KeyUID)
}
}
return nil
}
func (f *KeycardFlow) pair(kc *keycardContext) error {
if f.cardInfo.freeSlots == 0 {
return f.pauseAndRestart(SwapCard, FreeSlots)
}
if pairingPass, ok := f.params[PairingPass]; ok {
pairing, err := kc.pair(pairingPass.(string))
if err == nil {
return f.pairings.store(f.cardInfo.instanceUID, toPairInfo(pairing))
} else if isSCardError(err) {
return restartErr()
}
delete(f.params, PairingPass)
}
err := f.pauseAndWait(EnterPairing, "")
err := f.selectKeycard(kc)
if err != nil {
return err
return nil, err
}
return f.pair(kc)
}
func (f *KeycardFlow) initCard(kc *keycardContext) error {
//NOTE: after init a restart of the flow is always needed
return errors.New("not implemented")
}
func (f *KeycardFlow) openSC(kc *keycardContext) error {
if !kc.cmdSet.ApplicationInfo.Initialized {
return f.initCard(kc)
switch f.flowType {
case GetAppInfo:
return f.getAppInfoFlow(kc)
case RecoverAccount:
return f.recoverAccountFlow(kc)
case UnpairThis:
return f.unpairThisFlow(kc)
default:
return nil, errors.New(ErrorUnknownFlow)
}
pairing := f.pairings.get(f.cardInfo.instanceUID)
if pairing != nil {
err := kc.openSecureChannel(pairing.Index, pairing.Key)
if err == nil {
appStatus, err := kc.getStatusApplication()
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 isSCardError(err) {
return restartErr()
}
f.pairings.delete(f.cardInfo.instanceUID)
}
err := f.pair(kc)
if err != nil {
return err
}
return f.openSC(kc)
}
func (f *KeycardFlow) unblockPUK(kc *keycardContext) error {
return errors.New("not yet implemented")
}
func (f *KeycardFlow) authenticate(kc *keycardContext) error {
if f.cardInfo.pukRetries == 0 {
return f.pauseAndRestart(SwapCard, PUKRetries)
} else if f.cardInfo.pinRetries == 0 {
// succesful PUK unblock leaves the card authenticated
return f.unblockPUK(kc)
}
pinError := ""
if pin, ok := f.params[PIN]; ok {
err := kc.verifyPin(pin.(string))
if err == nil {
f.cardInfo.pinRetries = maxPINRetries
return nil
} else if isSCardError(err) {
return restartErr()
} else if leftRetries, ok := getPinRetries(err); ok {
f.cardInfo.pinRetries = leftRetries
}
pinError = PIN
}
err := f.pauseAndWait(EnterPIN, pinError)
if err != nil {
return err
}
return f.authenticate(kc)
}
func (f *KeycardFlow) openSCAndAuthenticate(kc *keycardContext) error {
err := f.openSC(kc)
if err != nil {
return err
}
return f.authenticate(kc)
}
func (f *KeycardFlow) getAppInfoFlow(kc *keycardContext) (FlowStatus, error) {
@ -377,3 +229,13 @@ func (f *KeycardFlow) recoverAccountFlow(kc *keycardContext) (FlowStatus, error)
return nil, errors.New("not yet implemented")
}
func (f *KeycardFlow) unpairThisFlow(kc *keycardContext) (FlowStatus, error) {
err := f.openSCAndAuthenticate(kc)
if err != nil {
return nil, err
}
return nil, errors.New("not yet implemented")
}

157
flow_commands.go Normal file
View File

@ -0,0 +1,157 @@
package statuskeycardgo
import "errors"
func (f *KeycardFlow) factoryReset(kc *keycardContext) error {
// on success, remove the FactoryReset switch to avoid re-triggering it
// if card is disconnected/reconnected
delete(f.params, FactoryReset)
return errors.New("not implemented")
}
func (f *KeycardFlow) selectKeycard(kc *keycardContext) error {
appInfo, err := kc.selectApplet()
f.cardInfo.instanceUID = tox(appInfo.InstanceUID)
f.cardInfo.keyUID = tox(appInfo.KeyUID)
f.cardInfo.freeSlots = bytesToInt(appInfo.AvailableSlots)
if err != nil {
return restartErr()
}
if !appInfo.Installed {
return f.pauseAndRestart(SwapCard, ErrorNotAKeycard)
}
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 *keycardContext) error {
if f.cardInfo.freeSlots == 0 {
return f.pauseAndRestart(SwapCard, FreeSlots)
}
if pairingPass, ok := f.params[PairingPass]; ok {
pairing, err := kc.pair(pairingPass.(string))
if err == nil {
return f.pairings.store(f.cardInfo.instanceUID, toPairInfo(pairing))
} else if isSCardError(err) {
return restartErr()
}
delete(f.params, PairingPass)
}
err := f.pauseAndWait(EnterPairing, "")
if err != nil {
return err
}
return f.pair(kc)
}
func (f *KeycardFlow) initCard(kc *keycardContext) error {
//NOTE: after init a restart of the flow is always needed
return errors.New("not implemented")
}
func (f *KeycardFlow) openSC(kc *keycardContext) error {
if !kc.cmdSet.ApplicationInfo.Initialized {
return f.initCard(kc)
}
pairing := f.pairings.get(f.cardInfo.instanceUID)
if pairing != nil {
err := kc.openSecureChannel(pairing.Index, pairing.Key)
if err == nil {
appStatus, err := kc.getStatusApplication()
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 isSCardError(err) {
return restartErr()
}
f.pairings.delete(f.cardInfo.instanceUID)
}
err := f.pair(kc)
if err != nil {
return err
}
return f.openSC(kc)
}
func (f *KeycardFlow) unblockPUK(kc *keycardContext) error {
return errors.New("not yet implemented")
}
func (f *KeycardFlow) authenticate(kc *keycardContext) error {
if f.cardInfo.pukRetries == 0 {
return f.pauseAndRestart(SwapCard, PUKRetries)
} else if f.cardInfo.pinRetries == 0 {
// succesful PUK unblock leaves the card authenticated
return f.unblockPUK(kc)
}
pinError := ""
if pin, ok := f.params[PIN]; ok {
err := kc.verifyPin(pin.(string))
if err == nil {
f.cardInfo.pinRetries = maxPINRetries
return nil
} else if isSCardError(err) {
return restartErr()
} else if leftRetries, ok := getPinRetries(err); ok {
f.cardInfo.pinRetries = leftRetries
}
pinError = PIN
}
err := f.pauseAndWait(EnterPIN, pinError)
if err != nil {
return err
}
return f.authenticate(kc)
}
func (f *KeycardFlow) openSCAndAuthenticate(kc *keycardContext) error {
err := f.openSC(kc)
if err != nil {
return err
}
return f.authenticate(kc)
}