session_test.go 15 KB
Newer Older
1
package sessiontest
Sietse Ringers's avatar
Sietse Ringers committed
2
3
4

import (
	"encoding/json"
5
	"reflect"
Sietse Ringers's avatar
Sietse Ringers committed
6
7
	"testing"

8
	"github.com/privacybydesign/irmago"
9
	"github.com/privacybydesign/irmago/internal/fs"
10
	"github.com/privacybydesign/irmago/internal/test"
11
	"github.com/privacybydesign/irmago/irmaclient"
Sietse Ringers's avatar
Sietse Ringers committed
12
13
14
15
	"github.com/stretchr/testify/require"
)

func TestSigningSession(t *testing.T) {
16
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
Sietse Ringers's avatar
Sietse Ringers committed
17
18
	request := getSigningRequest(id)
	sessionHelper(t, request, "signature", nil)
Sietse Ringers's avatar
Sietse Ringers committed
19
20
21
}

func TestDisclosureSession(t *testing.T) {
22
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
Sietse Ringers's avatar
Sietse Ringers committed
23
24
	request := getDisclosureRequest(id)
	sessionHelper(t, request, "verification", nil)
Sietse Ringers's avatar
Sietse Ringers committed
25
26
}

27
28
func TestNoAttributeDisclosureSession(t *testing.T) {
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard")
Sietse Ringers's avatar
Sietse Ringers committed
29
30
	request := getDisclosureRequest(id)
	sessionHelper(t, request, "verification", nil)
31
32
}

Sietse Ringers's avatar
Sietse Ringers committed
33
func TestIssuanceSession(t *testing.T) {
34
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
Sietse Ringers's avatar
Sietse Ringers committed
35
36
	request := getCombinedIssuanceRequest(id)
	sessionHelper(t, request, "issue", nil)
Sietse Ringers's avatar
Sietse Ringers committed
37
38
}

39
40
41
42
43
func TestMultipleIssuanceSession(t *testing.T) {
	request := getMultipleIssuanceRequest()
	sessionHelper(t, request, "issue", nil)
}

44
func TestDefaultCredentialValidity(t *testing.T) {
45
	client, _ := parseStorage(t)
Sietse Ringers's avatar
Sietse Ringers committed
46
47
	request := getIssuanceRequest(true)
	sessionHelper(t, request, "issue", client)
48
49
}

50
51
52
53
func TestIssuanceDisclosureEmptyAttributes(t *testing.T) {
	client, _ := parseStorage(t)
	defer test.ClearTestStorage(t)

54
	req := getNameIssuanceRequest()
55
56
57
58
59
60
61
	sessionHelper(t, req, "issue", client)

	// Test disclosing our null attribute
	req2 := getDisclosureRequest(irma.NewAttributeTypeIdentifier("irma-demo.MijnOverheid.fullName.prefix"))
	res := requestorSessionHelper(t, req2, client)
	require.Nil(t, res.Err)
	require.Nil(t, res.Disclosed[0][0].RawValue)
62
63
64
65
66
}

func TestIssuanceOptionalZeroLengthAttributes(t *testing.T) {
	req := getNameIssuanceRequest()
	req.Credentials[0].Attributes["prefix"] = ""
Sietse Ringers's avatar
Sietse Ringers committed
67
	sessionHelper(t, req, "issue", nil)
68
69
70
}

func TestIssuanceOptionalSetAttributes(t *testing.T) {
71
72
	req := getNameIssuanceRequest()
	req.Credentials[0].Attributes["prefix"] = "van"
Sietse Ringers's avatar
Sietse Ringers committed
73
	sessionHelper(t, req, "issue", nil)
74
75
}

76
func TestLargeAttribute(t *testing.T) {
77
	client, _ := parseStorage(t)
78
79
	defer test.ClearTestStorage(t)

80
81
	require.NoError(t, client.RemoveAllCredentials())

Sietse Ringers's avatar
Sietse Ringers committed
82
83
	issuanceRequest := getSpecialIssuanceRequest(false, "1234567890123456789012345678901234567890") // 40 chars
	sessionHelper(t, issuanceRequest, "issue", client)
84

Sietse Ringers's avatar
Sietse Ringers committed
85
86
	disclosureRequest := getDisclosureRequest(irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.university"))
	sessionHelper(t, disclosureRequest, "verification", client)
87
88
}

89
func TestIssuanceSingletonCredential(t *testing.T) {
90
	client, _ := parseStorage(t)
91
92
	defer test.ClearTestStorage(t)

93
	request := getMultipleIssuanceRequest()
94
95
	credid := irma.NewCredentialTypeIdentifier("irma-demo.MijnOverheid.root")

96
	require.Nil(t, client.Attributes(credid, 0))
97

Sietse Ringers's avatar
Sietse Ringers committed
98
	sessionHelper(t, request, "issue", client)
99
100
	require.NotNil(t, client.Attributes(credid, 0))
	require.Nil(t, client.Attributes(credid, 1))
101

Sietse Ringers's avatar
Sietse Ringers committed
102
	sessionHelper(t, request, "issue", client)
103
104
	require.NotNil(t, client.Attributes(credid, 0))
	require.Nil(t, client.Attributes(credid, 1))
105
106
}

107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
func TestUnsatisfiableDisclosureSession(t *testing.T) {
	client, _ := parseStorage(t)
	defer test.ClearTestStorage(t)

	request := irma.NewDisclosureRequest()
	request.Disclose = irma.AttributeConDisCon{
		irma.AttributeDisCon{
			irma.AttributeCon{
				irma.NewAttributeRequest("irma-demo.MijnOverheid.root.BSN"),
				irma.NewAttributeRequest("irma-demo.RU.studentCard.level"),
			},
			irma.AttributeCon{
				irma.NewAttributeRequest("test.test.mijnirma.email"),
				irma.NewAttributeRequest("irma-demo.MijnOverheid.fullName.firstname"),
				irma.NewAttributeRequest("irma-demo.MijnOverheid.fullName.familyname"),
			},
		},
		irma.AttributeDisCon{
			irma.AttributeCon{
				irma.NewAttributeRequest("irma-demo.RU.studentCard.level"),
			},
		},
	}

	missing := irmaclient.MissingAttributes{}
	require.NoError(t, json.Unmarshal([]byte(`{
		"0": [
			{
				"0": {"type": "irma-demo.MijnOverheid.root.BSN"}
			},
			{
				"1": {"type": "irma-demo.MijnOverheid.fullName.firstname"},
				"2": {"type": "irma-demo.MijnOverheid.fullName.familyname"}
			}
		]
	}`), &missing))
	require.True(t, reflect.DeepEqual(
		missing,
		requestorSessionHelper(t, request, client, sessionOptionUnsatisfiableRequest).Missing),
	)
}

149
150
151
152
153
154
155
/* There is an annoying difference between how Java and Go convert big integers to and from
byte arrays: in Java the sign of the integer is taken into account, but not in Go. This means
that in Java, when converting a bigint to or from a byte array, the most significant bit
indicates the sign of the integer. In Go this is not the case. This resulted in invalid
signatures being issued in the issuance protocol in two distinct ways, of which we test here
that they have been fixed. */
func TestAttributeByteEncoding(t *testing.T) {
156
	client, _ := parseStorage(t)
157
	defer test.ClearTestStorage(t)
158
159
160
161
162
163
164
	require.NoError(t, client.RemoveAllCredentials())

	/* After bitshifting the presence bit into the large attribute below, the most significant
	bit is 1. In the bigint->[]byte conversion that happens before hashing this attribute, in
	Java this results in an extra 0 byte being prepended in order to have a 0 instead as most
	significant (sign) bit. We test that the Java implementation correctly removes the extraneous
	0 byte. */
Sietse Ringers's avatar
Sietse Ringers committed
165
166
	request := getSpecialIssuanceRequest(false, "a23456789012345678901234567890")
	sessionHelper(t, request, "issue", client)
167
168
169
170
171
172
173

	/* After converting the attribute below to bytes (using UTF8, on which Java and Go do agree),
	the most significant bit of the byte version of this attribute is 1. In the []byte->bigint
	conversion that happens at that point in the Java implementation (bitshifting is done
	afterwards), this results in a negative number in Java and a positive number in Go. We test
	here that the Java correctly prepends a 0 byte just before this conversion in order to get
	the same positive bigint. */
Sietse Ringers's avatar
Sietse Ringers committed
174
175
	request = getSpecialIssuanceRequest(false, "é")
	sessionHelper(t, request, "issue", client)
176
177
}

178
179
180
181
182
183
184
185
186
187
188
189
func TestOutdatedClientIrmaConfiguration(t *testing.T) {
	client, _ := parseStorage(t)
	defer test.ClearTestStorage(t)

	// Remove old studentCard credential from before support for optional attributes, and issue a new one
	require.NoError(t, client.RemoveAllCredentials())
	require.Nil(t, requestorSessionHelper(t, getIssuanceRequest(true), client).Err)

	// client does not have updated irma_configuration with new attribute irma-demo.RU.studentCard.newAttribute,
	// and the server does. Disclose an attribute from this credential. The client implicitly discloses value 0
	// for the new attribute, and the server accepts.
	req := getDisclosureRequest(irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.level"))
190
	require.Nil(t, requestorSessionHelper(t, req, client, sessionOptionUpdatedIrmaConfiguration).Err)
191
192
}

193
func TestDisclosureNewAttributeUpdateSchemeManager(t *testing.T) {
194
	client, _ := parseStorage(t)
195
	defer test.ClearTestStorage(t)
196
197
198
199
200
201

	schemeid := irma.NewSchemeManagerIdentifier("irma-demo")
	credid := irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard")
	attrid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.newAttribute")
	require.False(t, client.Configuration.CredentialTypes[credid].ContainsAttribute(attrid))

202
203
204
	// Remove old studentCard credential from before support for optional attributes, and issue a new one
	require.NoError(t, client.RemoveAllCredentials())
	require.Nil(t, requestorSessionHelper(t, getIssuanceRequest(true), client).Err)
205

206
207
208
209
210
	// Trigger downloading the updated irma_configuration using a disclosure request containing the
	// new attribute, and inform the client
	client.Configuration.SchemeManagers[schemeid].URL = "http://localhost:48681/irma_configuration_updated/irma-demo"
	newAttrRequest := irma.NewDisclosureRequest(attrid)
	downloaded, err := client.Configuration.Download(newAttrRequest)
211
	require.NoError(t, err)
212
213
214
	require.NoError(t, client.ConfigurationUpdated(downloaded))

	// Our new attribute now exists in the configuration
215
	require.True(t, client.Configuration.CredentialTypes[credid].ContainsAttribute(attrid))
216
217
218
219
220
221
222
223
224

	// Disclose an old attribute (i.e. not newAttribute) to a server with an old configuration
	// Since our client has a new configuration it hides the new attribute that is not yet in the
	// server's configuration. All proofs are however valid as they should be and the server accepts.
	levelRequest := getDisclosureRequest(irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.level"))
	require.Nil(t, requestorSessionHelper(t, levelRequest, client).Err)

	// Disclose newAttribute to a server with a new configuration. This attribute was added
	// after we received a credential without it, so its value in this credential is 0.
225
	res := requestorSessionHelper(t, newAttrRequest, client, sessionOptionUpdatedIrmaConfiguration)
226
227
	require.Nil(t, res.Err)
	require.Nil(t, res.Disclosed[0][0].RawValue)
228
229
230
}

func TestIssueNewAttributeUpdateSchemeManager(t *testing.T) {
231
	client, _ := parseStorage(t)
232
233
	defer test.ClearTestStorage(t)

234
235
236
237
238
239
240
241
	schemeid := irma.NewSchemeManagerIdentifier("irma-demo")
	credid := irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard")
	attrid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.newAttribute")
	require.False(t, client.Configuration.CredentialTypes[credid].ContainsAttribute(attrid))

	client.Configuration.SchemeManagers[schemeid].URL = "http://localhost:48681/irma_configuration_updated/irma-demo"
	issuanceRequest := getIssuanceRequest(true)
	issuanceRequest.Credentials[0].Attributes["newAttribute"] = "foobar"
242
243
	_, err := client.Configuration.Download(issuanceRequest)
	require.NoError(t, err)
244
245
246
247
	require.True(t, client.Configuration.CredentialTypes[credid].ContainsAttribute(attrid))
}

func TestIssueOptionalAttributeUpdateSchemeManager(t *testing.T) {
248
	client, _ := parseStorage(t)
249
250
	defer test.ClearTestStorage(t)

251
252
253
254
255
256
257
258
	schemeid := irma.NewSchemeManagerIdentifier("irma-demo")
	credid := irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard")
	attrid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.level")
	require.False(t, client.Configuration.CredentialTypes[credid].AttributeType(attrid).IsOptional())

	client.Configuration.SchemeManagers[schemeid].URL = "http://localhost:48681/irma_configuration_updated/irma-demo"
	issuanceRequest := getIssuanceRequest(true)
	delete(issuanceRequest.Credentials[0].Attributes, "level")
259
260
	_, err := client.Configuration.Download(issuanceRequest)
	require.NoError(t, err)
261
262
263
	require.True(t, client.Configuration.CredentialTypes[credid].AttributeType(attrid).IsOptional())
}

Sietse Ringers's avatar
Sietse Ringers committed
264
func TestIssueNewCredTypeUpdateSchemeManager(t *testing.T) {
265
	client, _ := parseStorage(t)
Sietse Ringers's avatar
Sietse Ringers committed
266
267
268
269
270
271
272
273
	schemeid := irma.NewSchemeManagerIdentifier("irma-demo")
	credid := irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard")

	delete(client.Configuration.CredentialTypes, credid)
	require.NotContains(t, client.Configuration.CredentialTypes, credid)

	client.Configuration.SchemeManagers[schemeid].URL = "http://localhost:48681/irma_configuration_updated/irma-demo"
	request := getIssuanceRequest(true)
274
275
	_, err := client.Configuration.Download(request)
	require.NoError(t, err)
Sietse Ringers's avatar
Sietse Ringers committed
276
277
278
279
280
281
282

	require.Contains(t, client.Configuration.CredentialTypes, credid)

	test.ClearTestStorage(t)
}

func TestDisclosureNewCredTypeUpdateSchemeManager(t *testing.T) {
283
	client, _ := parseStorage(t)
Sietse Ringers's avatar
Sietse Ringers committed
284
285
286
287
288
289
290
291
	schemeid := irma.NewSchemeManagerIdentifier("irma-demo")
	credid := irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard")
	attrid := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.level")

	delete(client.Configuration.CredentialTypes, credid)
	require.NotContains(t, client.Configuration.CredentialTypes, credid)

	client.Configuration.SchemeManagers[schemeid].URL = "http://localhost:48681/irma_configuration_updated/irma-demo"
292
293
294
	request := irma.NewDisclosureRequest(attrid)
	_, err := client.Configuration.Download(request)
	require.NoError(t, err)
Sietse Ringers's avatar
Sietse Ringers committed
295
296
297
	require.Contains(t, client.Configuration.CredentialTypes, credid)

	test.ClearTestStorage(t)
298
299
300
}

func TestDisclosureNonexistingCredTypeUpdateSchemeManager(t *testing.T) {
301
	client, _ := parseStorage(t)
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
	request := irma.NewDisclosureRequest(
		irma.NewAttributeTypeIdentifier("irma-demo.RU.foo.bar"),
		irma.NewAttributeTypeIdentifier("irma-demo.baz.qux.abc"),
	)
	_, err := client.Configuration.Download(request)
	require.Error(t, err)

	expectedErr := &irma.UnknownIdentifierError{
		ErrorType: irma.ErrorUnknownIdentifier,
		Missing: &irma.IrmaIdentifierSet{
			SchemeManagers: map[irma.SchemeManagerIdentifier]struct{}{},
			PublicKeys:     map[irma.IssuerIdentifier][]int{},
			Issuers: map[irma.IssuerIdentifier]struct{}{
				irma.NewIssuerIdentifier("irma-demo.baz"): struct{}{},
			},
			CredentialTypes: map[irma.CredentialTypeIdentifier]struct{}{
				irma.NewCredentialTypeIdentifier("irma-demo.RU.foo"):  struct{}{},
				irma.NewCredentialTypeIdentifier("irma-demo.baz.qux"): struct{}{},
			},
		},
	}
	require.True(t, reflect.DeepEqual(expectedErr, err), "Download() returned incorrect missing identifier set")
Sietse Ringers's avatar
Sietse Ringers committed
324
325
}

326
327
328
329
// Test installing a new scheme manager from a qr, and do a(n issuance) session
// within this manager to test the autmatic downloading of credential definitions,
// issuers, and public keys.
func TestDownloadSchemeManager(t *testing.T) {
330
	client, _ := parseStorage(t)
331
	defer test.ClearTestStorage(t)
332
333
334
335
336
337
338
339
340
341
342
343
344
345

	// Remove irma-demo scheme manager as we need to test adding it
	irmademo := irma.NewSchemeManagerIdentifier("irma-demo")
	require.Contains(t, client.Configuration.SchemeManagers, irmademo)
	require.NoError(t, client.Configuration.RemoveSchemeManager(irmademo, true))
	require.NotContains(t, client.Configuration.SchemeManagers, irmademo)

	// Do an add-scheme-manager-session
	c := make(chan *SessionResult)
	qr, err := json.Marshal(&irma.SchemeManagerRequest{
		Type: irma.ActionSchemeManager,
		URL:  "http://localhost:48681/irma_configuration/irma-demo",
	})
	require.NoError(t, err)
346
	client.NewSession(string(qr), TestHandler{t, c, client, nil})
347
348
349
350
351
352
	if result := <-c; result != nil {
		require.NoError(t, result.Err)
	}
	require.Contains(t, client.Configuration.SchemeManagers, irmademo)

	// Do a session to test downloading of cred types, issuers and keys
Sietse Ringers's avatar
Sietse Ringers committed
353
354
	request := getCombinedIssuanceRequest(irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID"))
	sessionHelper(t, request, "issue", client)
355
356
357
358
359

	require.Contains(t, client.Configuration.SchemeManagers, irmademo)
	require.Contains(t, client.Configuration.Issuers, irma.NewIssuerIdentifier("irma-demo.RU"))
	require.Contains(t, client.Configuration.CredentialTypes, irma.NewCredentialTypeIdentifier("irma-demo.RU.studentCard"))

360
	basepath := test.FindTestdataFolder(t) + "/storage/test/irma_configuration/irma-demo"
361
362
363
364
365
366
367
368
369
370
	exists, err := fs.PathExists(basepath + "/description.xml")
	require.NoError(t, err)
	require.True(t, exists)
	exists, err = fs.PathExists(basepath + "/RU/description.xml")
	require.NoError(t, err)
	require.True(t, exists)
	exists, err = fs.PathExists(basepath + "/RU/Issues/studentCard/description.xml")
	require.NoError(t, err)
	require.True(t, exists)
}