Commit f81d74b1 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

Add new KeyshareBlocked message to session handler interface

parent e4d97606
......@@ -688,7 +688,7 @@ func (client *Client) keyshareEnrollWorker(managerID irma.SchemeManagerIdentifie
}
transport := irma.NewHTTPTransport(manager.KeyshareServer)
kss, err := newKeyshareServer(client.paillierKey(true), manager.KeyshareServer, email)
kss, err := newKeyshareServer(managerID, client.paillierKey(true), manager.KeyshareServer, email)
if err != nil {
return err
}
......
......@@ -7,9 +7,9 @@ import (
"math/big"
"strconv"
"github.com/privacybydesign/irmago"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
"github.com/privacybydesign/irmago"
)
// This file contains an implementation of the client side of the keyshare protocol,
......@@ -24,8 +24,9 @@ type KeysharePinRequestor interface {
type keyshareSessionHandler interface {
KeyshareDone(message interface{})
KeyshareCancelled()
KeyshareBlocked(duration int)
KeyshareError(err error)
KeyshareBlocked(manager irma.SchemeManagerIdentifier, duration int)
// In errors the manager may be nil, as not all keyshare errors have a clearly associated scheme manager
KeyshareError(manager *irma.SchemeManagerIdentifier, err error)
KeysharePin()
KeysharePinOK()
}
......@@ -43,11 +44,12 @@ type keyshareSession struct {
}
type keyshareServer struct {
URL string `json:"url"`
Username string `json:"username"`
Nonce []byte `json:"nonce"`
PrivateKey *paillierPrivateKey `json:"keyPair"`
token string
URL string `json:"url"`
Username string `json:"username"`
Nonce []byte `json:"nonce"`
PrivateKey *paillierPrivateKey `json:"keyPair"`
SchemeManagerIdentifier irma.SchemeManagerIdentifier
token string
}
type keyshareEnrollment struct {
......@@ -109,12 +111,17 @@ const (
kssPinError = "error"
)
func newKeyshareServer(privatekey *paillierPrivateKey, url, email string) (ks *keyshareServer, err error) {
func newKeyshareServer(
schemeManagerIdentifier irma.SchemeManagerIdentifier,
privatekey *paillierPrivateKey,
url, email string,
) (ks *keyshareServer, err error) {
ks = &keyshareServer{
Nonce: make([]byte, 32),
URL: url,
Username: email,
PrivateKey: privatekey,
Nonce: make([]byte, 32),
URL: url,
Username: email,
PrivateKey: privatekey,
SchemeManagerIdentifier: schemeManagerIdentifier,
}
_, err = rand.Read(ks.Nonce)
return
......@@ -148,14 +155,14 @@ func startKeyshareSession(
ksscount++
if _, enrolled := keyshareServers[managerID]; !enrolled {
err := errors.New("Not enrolled to keyshare server of scheme manager " + managerID.String())
sessionHandler.KeyshareError(err)
sessionHandler.KeyshareError(&managerID, err)
return
}
}
}
if _, issuing := session.(*irma.IssuanceRequest); issuing && ksscount > 1 {
err := errors.New("Issuance session involving more than one keyshare servers are not supported")
sessionHandler.KeyshareError(err)
sessionHandler.KeyshareError(nil, err)
return
}
......@@ -186,7 +193,7 @@ func startKeyshareSession(
authstatus := &keyshareAuthorization{}
err := transport.Post("users/isAuthorized", authstatus, "")
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&managerID, err)
return
}
switch authstatus.Status {
......@@ -194,7 +201,7 @@ func startKeyshareSession(
case kssTokenExpired:
requestPin = true
default:
ks.sessionHandler.KeyshareError(errors.New("Keyshare server returned unrecognized authorization status"))
ks.sessionHandler.KeyshareError(&managerID, errors.New("Keyshare server returned unrecognized authorization status"))
return
}
}
......@@ -215,13 +222,13 @@ func (ks *keyshareSession) VerifyPin(attempts int) {
ks.sessionHandler.KeyshareCancelled()
return
}
success, attemptsRemaining, blocked, err := ks.verifyPinAttempt(pin)
success, attemptsRemaining, blocked, manager, err := ks.verifyPinAttempt(pin)
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&manager, err)
return
}
if blocked != 0 {
ks.sessionHandler.KeyshareBlocked(blocked)
ks.sessionHandler.KeyshareBlocked(manager, blocked)
return
}
if success {
......@@ -242,14 +249,15 @@ func (ks *keyshareSession) VerifyPin(attempts int) {
// parameter.
// - If this or anything else (specified in err) goes wrong, success will be false.
// If all is ok, success will be true.
func (ks *keyshareSession) verifyPinAttempt(pin string) (success bool, tries int, blocked int, err error) {
for managerID := range ks.session.Identifiers().SchemeManagers {
if !ks.conf.SchemeManagers[managerID].Distributed() {
func (ks *keyshareSession) verifyPinAttempt(pin string) (
success bool, tries int, blocked int, manager irma.SchemeManagerIdentifier, err error) {
for manager = range ks.session.Identifiers().SchemeManagers {
if !ks.conf.SchemeManagers[manager].Distributed() {
continue
}
kss := ks.keyshareServers[managerID]
transport := ks.transports[managerID]
kss := ks.keyshareServers[manager]
transport := ks.transports[manager]
pinmsg := keysharePinMessage{Username: kss.Username, Pin: kss.HashedPin(pin)}
pinresult := &keysharePinStatus{}
err = transport.Post("users/verify/pin", pinresult, pinmsg)
......@@ -263,15 +271,9 @@ func (ks *keyshareSession) verifyPinAttempt(pin string) (success bool, tries int
transport.SetHeader(kssAuthHeader, kss.token)
case kssPinFailure:
tries, err = strconv.Atoi(pinresult.Message)
if err != nil {
return
}
return
case kssPinError:
blocked, err = strconv.Atoi(pinresult.Message)
if err != nil {
return
}
return
default:
err = errors.New("Keyshare server returned unrecognized PIN status")
......@@ -315,7 +317,7 @@ func (ks *keyshareSession) GetCommitments() {
comms := &proofPCommitmentMap{}
err := transport.Post("prove/getCommitments", comms, pkids[managerID])
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&managerID, err)
return
}
for pki, c := range comms.Commitments {
......@@ -350,7 +352,7 @@ func (ks *keyshareSession) GetProofPs() {
if !issuing {
bytes, err := ks.keyshareServer.PrivateKey.Encrypt(challenge.Bytes())
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&ks.keyshareServer.SchemeManagerIdentifier, err)
}
kssChallenge = new(big.Int).SetBytes(bytes)
}
......@@ -365,7 +367,7 @@ func (ks *keyshareSession) GetProofPs() {
var jwt string
err := transport.Post("prove/getResponse", &jwt, kssChallenge)
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&managerID, err)
return
}
responses[managerID] = jwt
......@@ -389,7 +391,7 @@ func (ks *keyshareSession) Finish(challenge *big.Int, responses map[irma.SchemeM
// issuance server to verify
list, err := ks.builders.BuildDistributedProofList(challenge, nil)
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&ks.keyshareServer.SchemeManagerIdentifier, err)
return
}
message := &gabi.IssueCommitmentMessage{Proofs: list, Nonce2: ks.state.nonce2}
......@@ -418,7 +420,7 @@ func (ks *keyshareSession) finishDisclosureOrSigning(challenge *big.Int, respons
ProofP *gabi.ProofP
}{}
if err := irma.JwtDecode(responses[managerID], &msg); err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&managerID, err)
return
}
......@@ -426,7 +428,7 @@ func (ks *keyshareSession) finishDisclosureOrSigning(challenge *big.Int, respons
proofPs[i] = msg.ProofP
bytes, err := ks.keyshareServer.PrivateKey.Decrypt(proofPs[i].SResponse.Bytes())
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(&managerID, err)
return
}
proofPs[i].SResponse = new(big.Int).SetBytes(bytes)
......@@ -435,7 +437,7 @@ func (ks *keyshareSession) finishDisclosureOrSigning(challenge *big.Int, respons
// Create merged proofs and finish protocol
list, err := ks.builders.BuildDistributedProofList(challenge, proofPs)
if err != nil {
ks.sessionHandler.KeyshareError(err)
ks.sessionHandler.KeyshareError(nil, err)
return
}
ks.sessionHandler.KeyshareDone(list)
......
......@@ -2,8 +2,9 @@ package irmaclient
import (
"fmt"
"github.com/privacybydesign/irmago"
"testing"
"github.com/privacybydesign/irmago"
)
type ManualSessionHandler struct {
......@@ -86,3 +87,6 @@ func (sh *ManualSessionHandler) Failure(irmaAction irma.Action, err *irma.Sessio
fmt.Println(err.Err)
sh.t.Fail()
}
func (sh *ManualSessionHandler) KeyshareBlocked(manager irma.SchemeManagerIdentifier, duration int) {
sh.Failure(irma.ActionUnknown, &irma.SessionError{ErrorType: irma.ErrorKeyshareBlocked})
}
......@@ -9,9 +9,9 @@ import (
"math/big"
"github.com/privacybydesign/irmago"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
"github.com/privacybydesign/irmago"
)
// This file contains the client side of the IRMA protocol, as well as the Handler interface
......@@ -31,7 +31,9 @@ type Handler interface {
Cancelled(action irma.Action)
Failure(action irma.Action, err *irma.SessionError)
UnsatisfiableRequest(action irma.Action, missing irma.AttributeDisjunctionList)
MissingKeyshareEnrollment(manager irma.SchemeManagerIdentifier)
KeyshareBlocked(manager irma.SchemeManagerIdentifier, duration int)
RequestIssuancePermission(request irma.IssuanceRequest, ServerName string, callback PermissionHandler)
RequestVerificationPermission(request irma.DisclosureRequest, ServerName string, callback PermissionHandler)
......@@ -65,7 +67,7 @@ type session struct {
irmaSession irma.IrmaSession
}
// We implement baseSessino for a session
// session implements baseSession
var _ baseSession = (*session)(nil)
// A interactiveSession is an interactive IRMA session
......@@ -458,15 +460,21 @@ func (session *manualSession) KeyshareCancelled() {
session.Handler.Cancelled(session.Action)
}
func (session *interactiveSession) KeyshareBlocked(duration int) {
session.fail(&irma.SessionError{ErrorType: irma.ErrorKeyshareBlocked, Info: strconv.Itoa(duration)})
func (session *interactiveSession) KeyshareBlocked(manager irma.SchemeManagerIdentifier, duration int) {
if session.delete() {
if session.downloaded != nil && !session.downloaded.Empty() {
session.client.handler.UpdateConfiguration(session.downloaded)
}
}
session.Handler.KeyshareBlocked(manager, duration)
}
func (session *manualSession) KeyshareBlocked(duration int) {
session.Handler.Failure(session.Action, &irma.SessionError{ErrorType: irma.ErrorKeyshareBlocked, Info: strconv.Itoa(duration)})
func (session *manualSession) KeyshareBlocked(manager irma.SchemeManagerIdentifier, duration int) {
// TODO: fire UpdateConfiguration()?
session.Handler.KeyshareBlocked(manager, duration)
}
func (session *interactiveSession) KeyshareError(err error) {
func (session *interactiveSession) KeyshareError(manager *irma.SchemeManagerIdentifier, err error) {
var serr *irma.SessionError
var ok bool
if serr, ok = err.(*irma.SessionError); !ok {
......@@ -477,7 +485,7 @@ func (session *interactiveSession) KeyshareError(err error) {
session.fail(serr)
}
func (session *manualSession) KeyshareError(err error) {
func (session *manualSession) KeyshareError(manager *irma.SchemeManagerIdentifier, err error) {
var serr *irma.SessionError
var ok bool
if serr, ok = err.(*irma.SessionError); !ok {
......
package irmaclient
// TODO +build integration
import (
"crypto/rand"
"encoding/base64"
......@@ -10,8 +8,8 @@ import (
"fmt"
"testing"
"github.com/privacybydesign/irmago"
"github.com/go-errors/errors"
"github.com/privacybydesign/irmago"
"github.com/stretchr/testify/require"
)
......@@ -21,6 +19,10 @@ type TestHandler struct {
client *Client
}
func (th TestHandler) KeyshareBlocked(manager irma.SchemeManagerIdentifier, duration int) {
th.Failure(irma.ActionUnknown, &irma.SessionError{ErrorType: irma.ErrorKeyshareBlocked})
}
func (th TestHandler) MissingKeyshareEnrollment(manager irma.SchemeManagerIdentifier) {
th.Failure(irma.ActionUnknown, &irma.SessionError{Err: errors.Errorf("Missing keyshare server %s", manager.String())})
}
......
......@@ -25,14 +25,16 @@ type update struct {
}
var clientUpdates = []func(client *Client) error{
// Convert old cardemu.xml Android storage to our own storage format
func(client *Client) error {
_, err := client.ParseAndroidStorage()
return err
},
// Adding scheme manager index, signature and public key
// Check the signatures of all scheme managers, if any is not ok,
// copy the entire irma_configuration folder from assets
func(client *Client) error {
// Adding scheme manager index, signature and public key
// Check the signatures of all scheme managers, if any is not ok,
// copy the entire irma_configuration folder from assets
conf := client.Configuration
if len(conf.DisabledSchemeManagers) > 0 {
return conf.CopyFromAssets(true)
......@@ -45,6 +47,8 @@ var clientUpdates = []func(client *Client) error{
}
return nil
},
// Rename config -> preferences
func(client *Client) (err error) {
exists, err := fs.PathExists(client.storage.path("config"))
if !exists || err != nil {
......@@ -63,6 +67,14 @@ var clientUpdates = []func(client *Client) error{
}
return client.storage.StorePreferences(client.Preferences)
},
// For each keyshare server, include in its struct the identifier of its scheme manager
func(client *Client) (err error) {
for smi, kss := range client.keyshareServers {
kss.SchemeManagerIdentifier = smi
}
return client.storage.StoreKeyshareServers(client.keyshareServers)
},
}
// update performs any function from clientUpdates that has not
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment