handle.go 6.05 KB
Newer Older
1
package core
2
3

import (
4
	"github.com/privacybydesign/gabi"
5
	"github.com/privacybydesign/irmago"
Sietse Ringers's avatar
Sietse Ringers committed
6
	"github.com/privacybydesign/irmago/server"
7
8
)

Sietse Ringers's avatar
Sietse Ringers committed
9
10
11
12
13
// This file contains the handler functions for the protocol messages, receiving and returning normally
// Go-typed messages here (JSON (un)marshalling is handled by the router).
// Maintaining the session state is done here, as well as checking whether the session is in the
// appropriate status before handling the request.

Sietse Ringers's avatar
Sietse Ringers committed
14
var conf *server.Configuration
15

16
func (session *session) handleDelete() {
17
	if session.status.Finished() {
18
		return
19
	}
20
	session.markAlive()
Sietse Ringers's avatar
Sietse Ringers committed
21

Sietse Ringers's avatar
Sietse Ringers committed
22
23
	session.result = &server.SessionResult{Token: session.token, Status: server.StatusCancelled}
	session.setStatus(server.StatusCancelled)
24
25
}

26
func (session *session) handleGetRequest(min, max *irma.ProtocolVersion) (irma.SessionRequest, *irma.RemoteError) {
Sietse Ringers's avatar
Sietse Ringers committed
27
28
	if session.status != server.StatusInitialized {
		return nil, server.RemoteError(server.ErrorUnexpectedRequest, "Session already started")
29
30
31
	}
	session.markAlive()

32
33
	var err error
	if session.version, err = chooseProtocolVersion(min, max); err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
34
		return nil, session.fail(server.ErrorProtocolVersion, "")
35
	}
36
	conf.Logger.Debugf("Using protocol version %s for session %s", session.version.String(), session.token)
37
	session.request.SetVersion(session.version)
38

Sietse Ringers's avatar
Sietse Ringers committed
39
	session.setStatus(server.StatusConnected)
40
	return session.request, nil
41
42
}

43
44
45
46
func (session *session) handleGetStatus() (server.Status, *irma.RemoteError) {
	return session.status, nil
}

47
func (session *session) handlePostSignature(signature *irma.SignedMessage) (*irma.ProofStatus, *irma.RemoteError) {
Sietse Ringers's avatar
Sietse Ringers committed
48
49
	if session.status != server.StatusConnected {
		return nil, server.RemoteError(server.ErrorUnexpectedRequest, "Session not yet started or already finished")
50
	}
51
	session.markAlive()
52

53
54
	var err error
	var rerr *irma.RemoteError
55
	session.result.Signature = signature
56
	session.result.Disclosed, session.result.ProofStatus, err = signature.Verify(
57
		conf.IrmaConfiguration, session.request.(*irma.SignatureRequest))
58
	if err == nil {
Sietse Ringers's avatar
Sietse Ringers committed
59
		session.setStatus(server.StatusDone)
60
61
	} else {
		if err == irma.ErrorMissingPublicKey {
Sietse Ringers's avatar
Sietse Ringers committed
62
			rerr = session.fail(server.ErrorUnknownPublicKey, err.Error())
63
		} else {
Sietse Ringers's avatar
Sietse Ringers committed
64
			rerr = session.fail(server.ErrorUnknown, err.Error())
65
66
67
		}
	}
	return &session.result.ProofStatus, rerr
68
}
69

Sietse Ringers's avatar
Sietse Ringers committed
70
func (session *session) handlePostDisclosure(disclosure irma.Disclosure) (*irma.ProofStatus, *irma.RemoteError) {
Sietse Ringers's avatar
Sietse Ringers committed
71
72
	if session.status != server.StatusConnected {
		return nil, server.RemoteError(server.ErrorUnexpectedRequest, "Session not yet started or already finished")
73
	}
74
	session.markAlive()
75

76
77
	var err error
	var rerr *irma.RemoteError
Sietse Ringers's avatar
Sietse Ringers committed
78
	session.result.Disclosed, session.result.ProofStatus, err = disclosure.Verify(
79
		conf.IrmaConfiguration, session.request.(*irma.DisclosureRequest))
80
	if err == nil {
Sietse Ringers's avatar
Sietse Ringers committed
81
		session.setStatus(server.StatusDone)
82
83
	} else {
		if err == irma.ErrorMissingPublicKey {
Sietse Ringers's avatar
Sietse Ringers committed
84
			rerr = session.fail(server.ErrorUnknownPublicKey, err.Error())
85
		} else {
Sietse Ringers's avatar
Sietse Ringers committed
86
			rerr = session.fail(server.ErrorUnknown, err.Error())
87
88
89
		}
	}
	return &session.result.ProofStatus, rerr
90
91
}

Sietse Ringers's avatar
Sietse Ringers committed
92
func (session *session) handlePostCommitments(commitments *irma.IssueCommitmentMessage) ([]*gabi.IssueSignatureMessage, *irma.RemoteError) {
Sietse Ringers's avatar
Sietse Ringers committed
93
94
	if session.status != server.StatusConnected {
		return nil, server.RemoteError(server.ErrorUnexpectedRequest, "Session not yet started or already finished")
Sietse Ringers's avatar
Sietse Ringers committed
95
96
	}
	session.markAlive()
97

Sietse Ringers's avatar
Sietse Ringers committed
98
99
100
	request := session.request.(*irma.IssuanceRequest)
	discloseCount := len(request.Disclose)
	if len(commitments.Proofs) != len(request.Credentials)+discloseCount {
Sietse Ringers's avatar
Sietse Ringers committed
101
		return nil, session.fail(server.ErrorAttributesMissing, "")
Sietse Ringers's avatar
Sietse Ringers committed
102
	}
103

Sietse Ringers's avatar
Sietse Ringers committed
104
105
106
107
	// Compute list of public keys against which to verify the received proofs
	disclosureproofs := irma.ProofList(commitments.Proofs[:discloseCount])
	pubkeys, err := disclosureproofs.ExtractPublicKeys(conf.IrmaConfiguration)
	if err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
108
		return nil, session.fail(server.ErrorInvalidProofs, err.Error())
Sietse Ringers's avatar
Sietse Ringers committed
109
110
111
112
113
114
	}
	for _, cred := range request.Credentials {
		iss := cred.CredentialTypeID.IssuerIdentifier()
		pubkey, _ := conf.IrmaConfiguration.PublicKey(iss, cred.KeyCounter) // No error, already checked earlier
		pubkeys = append(pubkeys, pubkey)
	}
115

Sietse Ringers's avatar
Sietse Ringers committed
116
117
118
119
120
121
122
	// Verify and merge keyshare server proofs, if any
	for i, proof := range commitments.Proofs {
		pubkey := pubkeys[i]
		schemeid := irma.NewIssuerIdentifier(pubkey.Issuer).SchemeManagerIdentifier()
		if conf.IrmaConfiguration.SchemeManagers[schemeid].Distributed() {
			proofP, err := session.getProofP(commitments, schemeid)
			if err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
123
				return nil, session.fail(server.ErrorKeyshareProofMissing, err.Error())
Sietse Ringers's avatar
Sietse Ringers committed
124
125
126
			}
			proof.MergeProofP(proofP, pubkey)
		}
127
128
	}

Sietse Ringers's avatar
Sietse Ringers committed
129
	// Verify all proofs and check disclosed attributes, if any, against request
Sietse Ringers's avatar
Sietse Ringers committed
130
	session.result.Disclosed, session.result.ProofStatus, err = commitments.Disclosure().VerifyAgainstDisjunctions(
Sietse Ringers's avatar
Sietse Ringers committed
131
		conf.IrmaConfiguration, request.Disclose, request.Context, request.Nonce, pubkeys, false)
132
133
	if err != nil {
		if err == irma.ErrorMissingPublicKey {
Sietse Ringers's avatar
Sietse Ringers committed
134
			return nil, session.fail(server.ErrorUnknownPublicKey, "")
135
		} else {
Sietse Ringers's avatar
Sietse Ringers committed
136
			return nil, session.fail(server.ErrorUnknown, "")
137
138
139
		}
	}
	if session.result.ProofStatus == irma.ProofStatusExpired {
Sietse Ringers's avatar
Sietse Ringers committed
140
		return nil, session.fail(server.ErrorAttributesExpired, "")
141
	}
Sietse Ringers's avatar
Sietse Ringers committed
142
	if session.result.ProofStatus != irma.ProofStatusValid {
Sietse Ringers's avatar
Sietse Ringers committed
143
		return nil, session.fail(server.ErrorInvalidProofs, "")
144
	}
Sietse Ringers's avatar
Sietse Ringers committed
145
146
147
148
149
150

	// Compute CL signatures
	var sigs []*gabi.IssueSignatureMessage
	for i, cred := range request.Credentials {
		id := cred.CredentialTypeID.IssuerIdentifier()
		pk, _ := conf.IrmaConfiguration.PublicKey(id, cred.KeyCounter)
151
152
		sk, _ := privatekey(id)
		issuer := gabi.NewIssuer(sk, pk, one)
Sietse Ringers's avatar
Sietse Ringers committed
153
154
155
		proof := commitments.Proofs[i+discloseCount].(*gabi.ProofU)
		attributes, err := cred.AttributeList(conf.IrmaConfiguration, 0x03)
		if err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
156
			return nil, session.fail(server.ErrorIssuanceFailed, err.Error())
Sietse Ringers's avatar
Sietse Ringers committed
157
158
159
		}
		sig, err := issuer.IssueSignature(proof.U, attributes.Ints, commitments.Nonce2)
		if err != nil {
Sietse Ringers's avatar
Sietse Ringers committed
160
			return nil, session.fail(server.ErrorIssuanceFailed, err.Error())
Sietse Ringers's avatar
Sietse Ringers committed
161
162
		}
		sigs = append(sigs, sig)
163
	}
Sietse Ringers's avatar
Sietse Ringers committed
164

Sietse Ringers's avatar
Sietse Ringers committed
165
	session.setStatus(server.StatusDone)
Sietse Ringers's avatar
Sietse Ringers committed
166
	return sigs, nil
167
}