session_test.go 13.7 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"
Sietse Ringers's avatar
Sietse Ringers committed
11
12
13
14
	"github.com/stretchr/testify/require"
)

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

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

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

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

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

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

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

53
	req := getNameIssuanceRequest()
54
55
56
57
58
59
60
	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)
61
62
63
64
65
}

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

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

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

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

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

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

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

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

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

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

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

106
107
108
109
110
111
112
/* 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) {
113
	client, _ := parseStorage(t)
114
	defer test.ClearTestStorage(t)
115
116
117
118
119
120
121
	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
122
123
	request := getSpecialIssuanceRequest(false, "a23456789012345678901234567890")
	sessionHelper(t, request, "issue", client)
124
125
126
127
128
129
130

	/* 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
131
132
	request = getSpecialIssuanceRequest(false, "é")
	sessionHelper(t, request, "issue", client)
133
134
}

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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"))
	require.Nil(t, requestorUpdatedSessionHelper(t, req, client).Err)
}

150
func TestDisclosureNewAttributeUpdateSchemeManager(t *testing.T) {
151
	client, _ := parseStorage(t)
152
	defer test.ClearTestStorage(t)
153
154
155
156
157
158

	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))

159
160
161
	// 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)
162

163
164
165
166
167
	// 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)
168
	require.NoError(t, err)
169
170
171
	require.NoError(t, client.ConfigurationUpdated(downloaded))

	// Our new attribute now exists in the configuration
172
	require.True(t, client.Configuration.CredentialTypes[credid].ContainsAttribute(attrid))
173
174
175
176
177
178
179
180
181
182
183
184

	// 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.
	res := requestorUpdatedSessionHelper(t, newAttrRequest, client)
	require.Nil(t, res.Err)
	require.Nil(t, res.Disclosed[0][0].RawValue)
185
186
187
}

func TestIssueNewAttributeUpdateSchemeManager(t *testing.T) {
188
	client, _ := parseStorage(t)
189
190
	defer test.ClearTestStorage(t)

191
192
193
194
195
196
197
198
	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"
199
200
	_, err := client.Configuration.Download(issuanceRequest)
	require.NoError(t, err)
201
202
203
204
	require.True(t, client.Configuration.CredentialTypes[credid].ContainsAttribute(attrid))
}

func TestIssueOptionalAttributeUpdateSchemeManager(t *testing.T) {
205
	client, _ := parseStorage(t)
206
207
	defer test.ClearTestStorage(t)

208
209
210
211
212
213
214
215
	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")
216
217
	_, err := client.Configuration.Download(issuanceRequest)
	require.NoError(t, err)
218
219
220
	require.True(t, client.Configuration.CredentialTypes[credid].AttributeType(attrid).IsOptional())
}

Sietse Ringers's avatar
Sietse Ringers committed
221
func TestIssueNewCredTypeUpdateSchemeManager(t *testing.T) {
222
	client, _ := parseStorage(t)
Sietse Ringers's avatar
Sietse Ringers committed
223
224
225
226
227
228
229
230
	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)
231
232
	_, err := client.Configuration.Download(request)
	require.NoError(t, err)
Sietse Ringers's avatar
Sietse Ringers committed
233
234
235
236
237
238
239

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

	test.ClearTestStorage(t)
}

func TestDisclosureNewCredTypeUpdateSchemeManager(t *testing.T) {
240
	client, _ := parseStorage(t)
Sietse Ringers's avatar
Sietse Ringers committed
241
242
243
244
245
246
247
248
	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"
249
250
251
	request := irma.NewDisclosureRequest(attrid)
	_, err := client.Configuration.Download(request)
	require.NoError(t, err)
Sietse Ringers's avatar
Sietse Ringers committed
252
253
254
	require.Contains(t, client.Configuration.CredentialTypes, credid)

	test.ClearTestStorage(t)
255
256
257
}

func TestDisclosureNonexistingCredTypeUpdateSchemeManager(t *testing.T) {
258
	client, _ := parseStorage(t)
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
	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
281
282
}

283
284
285
286
// 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) {
287
	client, _ := parseStorage(t)
288
	defer test.ClearTestStorage(t)
289
290
291
292
293
294
295
296
297
298
299
300
301
302

	// 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)
303
	client.NewSession(string(qr), TestHandler{t, c, client, nil})
304
305
306
307
308
309
	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
310
311
	request := getCombinedIssuanceRequest(irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID"))
	sessionHelper(t, request, "issue", client)
312
313
314
315
316

	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"))

317
	basepath := test.FindTestdataFolder(t) + "/storage/test/irma_configuration/irma-demo"
318
319
320
321
322
323
324
325
326
327
	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)
}