manual_session_test.go 12.9 KB
Newer Older
1
2
3
package irmaclient

import (
4
	"encoding/json"
Koen van Ingen's avatar
Koen van Ingen committed
5
	"fmt"
6

7
	"github.com/go-errors/errors"
8
	"github.com/privacybydesign/irmago/internal/test"
9
10
	"github.com/privacybydesign/irmago"
	"testing"
11
12
13
14
15
)

type ManualSessionHandler struct {
	permissionHandler PermissionHandler
	pinHandler        PinHandler
Koen van Ingen's avatar
Koen van Ingen committed
16
	t                 *testing.T
17
	errorChannel      chan *irma.SessionError
18
	resultChannel     chan *irma.SignatureProofResult
19
20
	sigRequest        *irma.SignatureRequest // Request used to create signature
	sigVerifyRequest  *irma.SignatureRequest // Request used to verify signature
21
22
23
24
}

var client *Client

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Issue BSN credential using sessionHelper
func issue(t *testing.T, ms ManualSessionHandler) {
	name := "testip"

	jwtcontents := getIssuanceJwt(name)
	sessionHandlerHelper(t, jwtcontents, "issue", client, &ms)
}

// Flip one bit in the proof string if invalidate is set to true
var invalidate bool

func corruptProofString(proof string) string {
	if invalidate {
		proofBytes := []byte(proof)

		flipLoc := 15
		if proofBytes[flipLoc] == 0x33 {
			proofBytes[flipLoc] = 0x32
		} else {
			proofBytes[flipLoc] = 0x33
		}
		return string(proofBytes)
	}
	return proof
}

51
52
53
// Create a ManualSessionHandler for unit tests
func createManualSessionHandler(request string, invalidRequest string, t *testing.T) ManualSessionHandler {
	errorChannel := make(chan *irma.SessionError)
54
	resultChannel := make(chan *irma.SignatureProofResult)
55

56
	sigRequestJSON := []byte(request)
57
	invalidSigRequestJSON := []byte(invalidRequest)
58
	sigRequest := &irma.SignatureRequest{}
59
	invalidSigRequest := &irma.SignatureRequest{}
60
	json.Unmarshal(sigRequestJSON, sigRequest)
61
62
63
64
65
66
67
68
69
70
71
72
73
	json.Unmarshal(invalidSigRequestJSON, invalidSigRequest)

	return ManualSessionHandler{
		t:                t,
		errorChannel:     errorChannel,
		resultChannel:    resultChannel,
		sigRequest:       sigRequest,
		sigVerifyRequest: invalidSigRequest,
	}
}

func TestManualSession(t *testing.T) {
	invalidate = false
74

75
76
77
78
79
80
81
82
83
84
85
86
	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"
	ms := createManualSessionHandler(request, request, t)

	client = parseStorage(t)
	client.NewManualSession(request, &ms)

	if err := <-ms.errorChannel; err != nil {
	  test.ClearTestStorage(t)
		t.Fatal(*err)
	}

	// No errors, obtain proof result from channel
87
	result := <-ms.resultChannel
88
89
	if ps := result.ProofStatus; ps != irma.VALID {
		t.Logf("Invalid proof result: %v Expected: %v", ps, irma.VALID)
90
91
		t.Fail()
	}
92
	if attrStatus := result.ToAttributeResultList().AttributeResults[0].AttributeProofStatus; attrStatus != irma.PRESENT {
93
		t.Logf("Invalid attribute result value: %v Expected: %v", attrStatus, irma.PRESENT)
94
		t.Fail()
95
	}
96
97
	test.ClearTestStorage(t)
}
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Test if the session fails with unsatisfiable error if we cannot satify the signature request
func TestManualSessionUnsatisfiable(t *testing.T) {
	invalidate = false

	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":{\"irma-demo.RU.studentCard.studentID\": \"123\"}}]}"
	ms := createManualSessionHandler(request, request, t)

	client = parseStorage(t)
	client.NewManualSession(request, &ms)

	// Fail test if we won't get UnsatisfiableRequest error
	if err := <-ms.errorChannel; err.ErrorType != irma.ErrorType("UnsatisfiableRequest") {
	  test.ClearTestStorage(t)
		t.Fatal(*err)
	}
	test.ClearTestStorage(t)
}

// Test if proof verification fails with status 'ERROR_CRYPTO' if we verify it with an invalid nonce
func TestManualSessionInvalidNonce(t *testing.T) {
	invalidate = false

	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"
	invalidRequest := "{\"nonce\": 1, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"

	ms := createManualSessionHandler(request, invalidRequest, t)

	client = parseStorage(t)
127
	client.NewManualSession(request, &ms)
128

129
	if err := <-ms.errorChannel; err != nil {
130
	  test.ClearTestStorage(t)
131
132
		t.Fatal(*err)
	}
133

134
	// No errors, obtain proof result from channel
135
136
	if result := <-ms.resultChannel; result.ProofStatus != irma.INVALID_CRYPTO {
		t.Logf("Invalid proof result: %v Expected: %v", result.ProofStatus, irma.INVALID_CRYPTO)
137
138
		t.Fail()
	}
139
	test.ClearTestStorage(t)
140
141
}

142
143
// Test if proof verification fails with status 'MISSING_ATTRIBUTES' if we provide it with a non-matching signature request
func TestManualSessionInvalidRequest(t *testing.T) {
144
145
	invalidate = false

146
147
148
149
150
151
152
153
154
155
156
157
	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"
	invalidRequest := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.university\"]}]}"

	ms := createManualSessionHandler(request, invalidRequest, t)

	client = parseStorage(t)
	client.NewManualSession(request, &ms)

	if err := <-ms.errorChannel; err != nil {
	  test.ClearTestStorage(t)
		t.Fatal(*err)
	}
158

159
	// No errors, obtain proof result from channel
160
	result := <-ms.resultChannel
161
162
	if ps := result.ProofStatus; ps != irma.MISSING_ATTRIBUTES {
		t.Logf("Invalid proof result: %v Expected: %v", ps, irma.MISSING_ATTRIBUTES)
163
164
		t.Fail()
	}
165
166
167
168

	// First attribute result is MISSING, because it is in the request but not disclosed
	if attrStatus := result.ToAttributeResultList().AttributeResults[0].AttributeProofStatus; attrStatus != irma.MISSING {
		t.Logf("Invalid attribute result value: %v Expected: %v", attrStatus, irma.MISSING)
169
170
		t.Fail()
	}
171
172
173
	// Second attribute result is EXTRA, since it is disclosed, but not matching the sigrequest
	if attrStatus := result.ToAttributeResultList().AttributeResults[1].AttributeProofStatus; attrStatus != irma.EXTRA {
		t.Logf("Invalid attribute result value: %v Expected: %v", attrStatus, irma.EXTRA)
174
		t.Fail()
175
	}
176
177
178
179
180
181
182
183
184
185
186
	test.ClearTestStorage(t)
}

// Test if proof verification fails with status 'MISSING_ATTRIBUTES' if we provide it with invalid attribute values
func TestManualSessionInvalidAttributeValue(t *testing.T) {
	invalidate = false

	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":{\"irma-demo.RU.studentCard.studentID\": \"456\"}}]}"
	invalidRequest := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":{\"irma-demo.RU.studentCard.studentID\": \"123\"}}]}"

	ms := createManualSessionHandler(request, invalidRequest, t)
187
188

	client = parseStorage(t)
189
	client.NewManualSession(request, &ms)
190

191
192
193
194
195
196
	if err := <-ms.errorChannel; err != nil {
	  test.ClearTestStorage(t)
		t.Fatal(*err)
	}

	// No errors, obtain proof result from channel
197
	result := <-ms.resultChannel
198
199
	if ps := result.ProofStatus; ps != irma.MISSING_ATTRIBUTES {
		t.Logf("Invalid proof result: %v Expected: %v", ps, irma.MISSING_ATTRIBUTES)
200
201
		t.Fail()
	}
202
	if attrStatus := result.ToAttributeResultList().AttributeResults[0].AttributeProofStatus; attrStatus != irma.INVALID_VALUE {
203
		t.Logf("Invalid attribute result value: %v Expected: %v", attrStatus, irma.INVALID_VALUE)
204
205
206
207
208
209
210
211
212
		t.Fail()
	}
	test.ClearTestStorage(t)
}

func TestManualKeyShareSession(t *testing.T) {
	invalidate = false

	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"test.test.mijnirma.email\"]}]}"
213

214
215
216
217
218
219
	ms := createManualSessionHandler(request, request, t)

	client = parseStorage(t)
	client.NewManualSession(request, &ms)

	if err := <-ms.errorChannel; err != nil {
220
	  test.ClearTestStorage(t)
221
222
		t.Fatal(*err)
	}
223
224

	// No errors, obtain proof result from channel
225
226
	if result := <-ms.resultChannel; result.ProofStatus != irma.VALID {
		t.Logf("Invalid proof result: %v Expected: %v", result.ProofStatus, irma.VALID)
227
228
		t.Fail()
	}
229
	test.ClearTestStorage(t)
230
231
232
233
}

func TestManualSessionMultiProof(t *testing.T) {
	invalidate = false
234
235
	client = parseStorage(t)

236
	// First, we need to issue an extra credential (BSN)
237
	is := ManualSessionHandler{t: t, errorChannel: make(chan *irma.SessionError)}
238
	go issue(t, is)
239
	if err := <-is.errorChannel; err != nil {
240
241
242
243
244
245
		fmt.Println("Error during initial issueing!")
		t.Fatal(*err)
	}

	// Request to sign with both BSN and StudentID
	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]},{\"label\":\"BSN\",\"attributes\":[\"irma-demo.MijnOverheid.root.BSN\"]}]}"
246

247
	ms := createManualSessionHandler(request, request, t)
248

249
	client.NewManualSession(request, &ms)
250

251
	if err := <-ms.errorChannel; err != nil {
252
	  test.ClearTestStorage(t)
253
254
		t.Fatal(*err)
	}
255
256

	// No errors, obtain proof result from channel
257
258
259
260
261
262
263
264
265
266
267
	result := <-ms.resultChannel
	if ps := result.ProofStatus; ps != irma.VALID {
		t.Logf("Invalid proof result: %v Expected: %v", result.ProofStatus, irma.VALID)
		t.Fail()
	}
	if attrStatus := result.ToAttributeResultList().AttributeResults[0].AttributeProofStatus; attrStatus != irma.PRESENT {
		t.Logf("Invalid attribute result value: %v Expected: %v", attrStatus, irma.PRESENT)
		t.Fail()
	}
	if attrStatus := result.ToAttributeResultList().AttributeResults[1].AttributeProofStatus; attrStatus != irma.PRESENT {
		t.Logf("Invalid attribute result value: %v Expected: %v", attrStatus, irma.PRESENT)
268
269
		t.Fail()
	}
270
	test.ClearTestStorage(t)
271
272
}

273
274
275
276
func TestManualSessionInvalidProof(t *testing.T) {
	invalidate = true

	request := "{\"nonce\": 0, \"context\": 0, \"message\":\"I owe you everything\",\"messageType\":\"STRING\",\"content\":[{\"label\":\"Student number (RU)\",\"attributes\":[\"irma-demo.RU.studentCard.studentID\"]}]}"
277
	ms := createManualSessionHandler(request, request, t)
278

279
	client = parseStorage(t)
280
281
	client.NewManualSession(request, &ms)

282
283
	if err := <-ms.errorChannel; err != nil {
	  test.ClearTestStorage(t)
284
285
		t.Fatal(*err)
	}
286
287

	// No errors, obtain proof result from channel
288
289
	if result := <-ms.resultChannel; result.ProofStatus != irma.INVALID_CRYPTO {
		t.Logf("Invalid proof result: %v Expected: %v", result.ProofStatus, irma.INVALID_CRYPTO)
290
291
		t.Fail()
	}
292
	test.ClearTestStorage(t)
293
294
}

295
func (sh *ManualSessionHandler) Success(irmaAction irma.Action, result string) {
296
297
298
299
300
	switch irmaAction {
	case irma.ActionSigning:
		// Make proof corrupt if we want to test invalid proofs
		result = corruptProofString(result)

301
		go func() {
302
			sh.resultChannel <- irma.VerifySig(client.Configuration, result, sh.sigVerifyRequest)
303
		}()
304
	}
305
	sh.errorChannel <- nil
306
}
307
308
309
func (sh *ManualSessionHandler) UnsatisfiableRequest(irmaAction irma.Action, missingAttributes irma.AttributeDisjunctionList) {
	// This function is called from main thread, which blocks go channel, so need go routine here
	go func() {
310
		sh.errorChannel <- &irma.SessionError{
311
312
313
			ErrorType: irma.ErrorType("UnsatisfiableRequest"),
		}
	}()
Koen van Ingen's avatar
Koen van Ingen committed
314
}
315

Koen van Ingen's avatar
Koen van Ingen committed
316
func (sh *ManualSessionHandler) StatusUpdate(irmaAction irma.Action, status irma.Status) {}
317

318
319
320
321
func (sh *ManualSessionHandler) RequestPin(remainingAttempts int, ph PinHandler) {
	ph(true, "12345")
}
func (sh *ManualSessionHandler) RequestSignaturePermission(request irma.SignatureRequest, requesterName string, ph PermissionHandler) {
322
323
324
325
326
	var attributes []*irma.AttributeIdentifier
	for _, cand := range request.Candidates {
		attributes = append(attributes, cand[0])
	}
	c := irma.DisclosureChoice{attributes}
327
328
	ph(true, &c)
}
329
330
331
func (sh *ManualSessionHandler) RequestIssuancePermission(request irma.IssuanceRequest, issuerName string, ph PermissionHandler) {
	ph(true, nil)
}
332

333
// These handlers should not be called, fail test if they are called
334
func (sh *ManualSessionHandler) Cancelled(irmaAction irma.Action) {
335
	sh.errorChannel <- &irma.SessionError{Err: errors.New("Session was cancelled")}
336
}
337
338
func (sh *ManualSessionHandler) MissingKeyshareEnrollment(manager irma.SchemeManagerIdentifier) {
	sh.errorChannel <- &irma.SessionError{Err: errors.Errorf("Missing keyshare server %s", manager.String())}
Koen van Ingen's avatar
Koen van Ingen committed
339
340
}
func (sh *ManualSessionHandler) RequestSchemeManagerPermission(manager *irma.SchemeManager, callback func(proceed bool)) {
341
	sh.errorChannel <- &irma.SessionError{Err: errors.New("Unexpected session type")}
Koen van Ingen's avatar
Koen van Ingen committed
342
343
}
func (sh *ManualSessionHandler) RequestVerificationPermission(request irma.DisclosureRequest, verifierName string, ph PermissionHandler) {
344
	sh.errorChannel <- &irma.SessionError{Err: errors.New("Unexpected session type")}
Koen van Ingen's avatar
Koen van Ingen committed
345
}
346
347
func (sh *ManualSessionHandler) Failure(irmaAction irma.Action, err *irma.SessionError) {
	fmt.Println(err.Err)
348
	sh.errorChannel <- err
349
}