Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
IRMA
Github mirrors
irmago
Commits
8e5e0cb7
Commit
8e5e0cb7
authored
Jun 16, 2019
by
Sietse Ringers
Browse files
fix: handling and data structure of missing attributes in irmaclient during unsatisfiable requests
parent
0e3802dc
Changes
7
Hide whitespace changes
Inline
Side-by-side
internal/sessiontest/handlers_test.go
View file @
8e5e0cb7
...
...
@@ -96,7 +96,7 @@ func (th TestHandler) Failure(err *irma.SessionError) {
th
.
t
.
Fatal
(
err
)
}
}
func
(
th
TestHandler
)
UnsatisfiableRequest
(
request
irma
.
SessionRequest
,
serverName
irma
.
TranslatedString
,
missing
map
[
int
]
map
[
int
]
irma
.
Attribute
Con
)
{
func
(
th
TestHandler
)
UnsatisfiableRequest
(
request
irma
.
SessionRequest
,
serverName
irma
.
TranslatedString
,
missing
irmaclient
.
Missing
Attribute
s
)
{
th
.
Failure
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorType
(
"UnsatisfiableRequest"
),
})
...
...
@@ -128,6 +128,19 @@ type SessionResult struct {
Err
error
SignatureResult
*
irma
.
SignedMessage
DisclosureResult
*
irma
.
Disclosure
Missing
irmaclient
.
MissingAttributes
}
type
UnsatisfiableTestHandler
struct
{
TestHandler
}
func
(
th
UnsatisfiableTestHandler
)
UnsatisfiableRequest
(
request
irma
.
SessionRequest
,
serverName
irma
.
TranslatedString
,
missing
irmaclient
.
MissingAttributes
)
{
th
.
c
<-
&
SessionResult
{
Missing
:
missing
}
}
func
(
th
UnsatisfiableTestHandler
)
Success
(
result
string
)
{
th
.
Failure
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorType
(
"Unsatisfiable request succeeded"
)})
}
// ManualTestHandler embeds a TestHandler to inherit its methods.
...
...
internal/sessiontest/requestor_test.go
View file @
8e5e0cb7
...
...
@@ -12,24 +12,27 @@ import (
"github.com/stretchr/testify/require"
)
func
requestorSessionHelper
(
t
*
testing
.
T
,
request
irma
.
SessionRequest
,
client
*
irmaclient
.
Client
)
*
server
.
SessionResult
{
StartIrmaServer
(
t
,
false
)
defer
StopIrmaServer
()
return
requestorSesionWorker
(
t
,
request
,
client
)
}
type
sessionOption
int
func
requestorUpdatedSessionHelper
(
t
*
testing
.
T
,
request
irma
.
SessionRequest
,
client
*
irmaclient
.
Client
)
*
server
.
SessionResult
{
StartIrmaServer
(
t
,
true
)
defer
StopIrmaServer
()
return
requestorSesionWorker
(
t
,
request
,
client
)
const
(
sessionOptionUpdatedIrmaConfiguration
=
iota
sessionOptionUnsatisfiableRequest
)
type
requestorSessionResult
struct
{
*
server
.
SessionResult
Missing
irmaclient
.
MissingAttributes
}
func
requestorSesion
Work
er
(
t
*
testing
.
T
,
request
irma
.
SessionRequest
,
client
*
irmaclient
.
Client
)
*
server
.
SessionResult
{
func
requestorSes
s
ion
Help
er
(
t
*
testing
.
T
,
request
irma
.
SessionRequest
,
client
*
irmaclient
.
Client
,
options
...
sessionOption
)
*
requestor
SessionResult
{
if
client
==
nil
{
client
,
_
=
parseStorage
(
t
)
defer
test
.
ClearTestStorage
(
t
)
}
StartIrmaServer
(
t
,
len
(
options
)
==
1
&&
options
[
0
]
==
sessionOptionUpdatedIrmaConfiguration
)
defer
StopIrmaServer
()
clientChan
:=
make
(
chan
*
SessionResult
)
serverChan
:=
make
(
chan
*
server
.
SessionResult
)
...
...
@@ -38,7 +41,12 @@ func requestorSesionWorker(t *testing.T, request irma.SessionRequest, client *ir
})
require
.
NoError
(
t
,
err
)
h
:=
TestHandler
{
t
,
clientChan
,
client
,
nil
}
var
h
irmaclient
.
Handler
if
len
(
options
)
==
1
&&
options
[
0
]
==
sessionOptionUnsatisfiableRequest
{
h
=
UnsatisfiableTestHandler
{
TestHandler
{
t
,
clientChan
,
client
,
nil
}}
}
else
{
h
=
TestHandler
{
t
,
clientChan
,
client
,
nil
}
}
j
,
err
:=
json
.
Marshal
(
qr
)
require
.
NoError
(
t
,
err
)
client
.
NewSession
(
string
(
j
),
h
)
...
...
@@ -47,10 +55,13 @@ func requestorSesionWorker(t *testing.T, request irma.SessionRequest, client *ir
require
.
NoError
(
t
,
clientResult
.
Err
)
}
serverResult
:=
<-
serverChan
require
.
Equal
(
t
,
token
,
serverResult
.
Token
)
return
serverResult
if
len
(
options
)
==
1
&&
options
[
0
]
==
sessionOptionUnsatisfiableRequest
{
return
&
requestorSessionResult
{
nil
,
clientResult
.
Missing
}
}
else
{
serverResult
:=
<-
serverChan
require
.
Equal
(
t
,
token
,
serverResult
.
Token
)
return
&
requestorSessionResult
{
serverResult
,
nil
}
}
}
// Check that nonexistent IRMA identifiers in the session request fail the session
...
...
@@ -110,7 +121,7 @@ func testRequestorDisclosure(t *testing.T, request *irma.DisclosureRequest) *ser
serverResult
:=
requestorSessionHelper
(
t
,
request
,
nil
)
require
.
Nil
(
t
,
serverResult
.
Err
)
require
.
Equal
(
t
,
irma
.
ProofStatusValid
,
serverResult
.
ProofStatus
)
return
serverResult
return
serverResult
.
SessionResult
}
func
TestRequestorIssuanceSession
(
t
*
testing
.
T
)
{
...
...
internal/sessiontest/session_test.go
View file @
8e5e0cb7
...
...
@@ -8,6 +8,7 @@ import (
"github.com/privacybydesign/irmago"
"github.com/privacybydesign/irmago/internal/fs"
"github.com/privacybydesign/irmago/internal/test"
"github.com/privacybydesign/irmago/irmaclient"
"github.com/stretchr/testify/require"
)
...
...
@@ -103,6 +104,48 @@ func TestIssuanceSingletonCredential(t *testing.T) {
require
.
Nil
(
t
,
client
.
Attributes
(
credid
,
1
))
}
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
),
)
}
/* 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
...
...
@@ -144,7 +187,7 @@ func TestOutdatedClientIrmaConfiguration(t *testing.T) {
// 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
,
requestor
Updated
SessionHelper
(
t
,
req
,
client
)
.
Err
)
require
.
Nil
(
t
,
requestorSessionHelper
(
t
,
req
,
client
,
sessionOptionUpdatedIrmaConfiguration
)
.
Err
)
}
func
TestDisclosureNewAttributeUpdateSchemeManager
(
t
*
testing
.
T
)
{
...
...
@@ -179,7 +222,7 @@ func TestDisclosureNewAttributeUpdateSchemeManager(t *testing.T) {
// 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
:=
requestor
Updated
SessionHelper
(
t
,
newAttrRequest
,
client
)
res
:=
requestorSessionHelper
(
t
,
newAttrRequest
,
client
,
sessionOptionUpdatedIrmaConfiguration
)
require
.
Nil
(
t
,
res
.
Err
)
require
.
Nil
(
t
,
res
.
Disclosed
[
0
][
0
]
.
RawValue
)
}
...
...
irmaclient/client.go
View file @
8e5e0cb7
...
...
@@ -93,6 +93,14 @@ type ClientHandler interface {
UpdateAttributes
()
}
// MissingAttributes contains all attribute requests that the client cannot satisfy with its
// current attributes.
type
MissingAttributes
map
[
int
][]
map
[
int
]
MissingAttribute
// MissingAttribute is an irma.AttributeRequest that is satisfied by none of the client's attributes
// (with Go's default JSON marshaler instead of that of irma.AttributeRequest).
type
MissingAttribute
irma
.
AttributeRequest
type
secretKey
struct
{
Key
*
big
.
Int
}
...
...
@@ -513,7 +521,7 @@ func cartesianProduct(candidates [][]*irma.CredentialIdentifier) credCandidateSe
// currently posesses (ie. len(candidates) == 0), then the second return parameter lists the missing
// attributes that would be necessary to satisfy the disjunction.
func
(
client
*
Client
)
Candidates
(
discon
irma
.
AttributeDisCon
)
(
candidates
[][]
*
irma
.
AttributeIdentifier
,
missing
map
[
int
]
irma
.
Attribute
Con
,
candidates
[][]
*
irma
.
AttributeIdentifier
,
missing
[]
map
[
int
]
Missing
Attribute
,
)
{
candidates
=
[][]
*
irma
.
AttributeIdentifier
{}
...
...
@@ -558,22 +566,24 @@ func (client *Client) Candidates(discon irma.AttributeDisCon) (
// missingAttributes returns for each of the conjunctions in the specified disjunction
// a list of attributes that the client does not posess but which would be required to
// satisfy the conjunction.
func
(
client
*
Client
)
missingAttributes
(
discon
irma
.
AttributeDisCon
)
map
[
int
]
irma
.
Attribute
Con
{
missing
:=
ma
p
[
int
]
irma
.
AttributeCon
{}
func
(
client
*
Client
)
missingAttributes
(
discon
irma
.
AttributeDisCon
)
[]
map
[
int
]
Missing
Attribute
{
missing
:=
ma
ke
([]
map
[
int
]
MissingAttribute
,
len
(
discon
))
for
i
,
con
:=
range
discon
{
for
_
,
attr
:=
range
con
{
creds
:=
client
.
attributes
[
attr
.
Type
.
CredentialTypeIdentifier
()]
missing
[
i
]
=
map
[
int
]
MissingAttribute
{}
conloop
:
for
j
,
req
:=
range
con
{
creds
:=
client
.
attributes
[
req
.
Type
.
CredentialTypeIdentifier
()]
if
len
(
creds
)
==
0
{
missing
[
i
]
=
append
(
missing
[
i
],
attr
)
missing
[
i
]
[
j
]
=
MissingAttribute
(
req
)
continue
}
for
_
,
cred
:=
range
creds
{
if
attr
.
Satisfy
(
attr
.
Type
,
cred
.
UntranslatedAttribute
(
attr
.
Type
))
{
continue
if
req
.
Satisfy
(
req
.
Type
,
cred
.
UntranslatedAttribute
(
req
.
Type
))
{
continue
conloop
}
}
missing
[
i
]
=
append
(
missing
[
i
],
attr
)
missing
[
i
]
[
j
]
=
MissingAttribute
(
req
)
}
}
...
...
@@ -584,13 +594,13 @@ func (client *Client) missingAttributes(discon irma.AttributeDisCon) map[int]irm
// to satisfy the specifed disjunction list. If not, the unsatisfiable disjunctions
// are returned.
func
(
client
*
Client
)
CheckSatisfiability
(
condiscon
irma
.
AttributeConDisCon
)
(
candidates
[][][]
*
irma
.
AttributeIdentifier
,
missing
map
[
int
]
map
[
int
]
irma
.
Attribute
Con
,
candidates
[][][]
*
irma
.
AttributeIdentifier
,
missing
Missing
Attribute
s
,
)
{
candidates
=
make
([][][]
*
irma
.
AttributeIdentifier
,
len
(
condiscon
))
missing
=
map
[
int
]
map
[
int
]
irma
.
Attribute
Con
{}
missing
=
Missing
Attribute
s
{}
for
i
,
discon
:=
range
condiscon
{
var
m
map
[
int
]
irma
.
Attribute
Con
var
m
[]
map
[
int
]
Missing
Attribute
candidates
[
i
],
m
=
client
.
Candidates
(
discon
)
if
len
(
candidates
[
i
])
==
0
{
missing
[
i
]
=
m
...
...
irmaclient/handlers.go
View file @
8e5e0cb7
...
...
@@ -80,6 +80,6 @@ func (h *keyshareEnrollmentHandler) KeyshareEnrollmentDeleted(manager irma.Schem
func
(
h
*
keyshareEnrollmentHandler
)
KeyshareEnrollmentMissing
(
manager
irma
.
SchemeManagerIdentifier
)
{
h
.
fail
(
errors
.
New
(
"Keyshare enrollment failed: unenrolled"
))
}
func
(
h
*
keyshareEnrollmentHandler
)
UnsatisfiableRequest
(
request
irma
.
SessionRequest
,
ServerName
irma
.
TranslatedString
,
missing
map
[
int
]
map
[
int
]
irma
.
Attribute
Con
)
{
func
(
h
*
keyshareEnrollmentHandler
)
UnsatisfiableRequest
(
request
irma
.
SessionRequest
,
ServerName
irma
.
TranslatedString
,
missing
Missing
Attribute
s
)
{
h
.
fail
(
errors
.
New
(
"Keyshare enrollment failed: unsatisfiable"
))
}
irmaclient/session.go
View file @
8e5e0cb7
...
...
@@ -34,7 +34,7 @@ type Handler interface {
Failure
(
err
*
irma
.
SessionError
)
UnsatisfiableRequest
(
request
irma
.
SessionRequest
,
ServerName
irma
.
TranslatedString
,
missing
map
[
int
]
map
[
int
]
irma
.
Attribute
Con
)
missing
Missing
Attribute
s
)
KeyshareBlocked
(
manager
irma
.
SchemeManagerIdentifier
,
duration
int
)
KeyshareEnrollmentIncomplete
(
manager
irma
.
SchemeManagerIdentifier
)
...
...
requests.go
View file @
8e5e0cb7
...
...
@@ -174,8 +174,8 @@ type DisclosureChoice struct {
// a specified value, in a session request.
type
AttributeRequest
struct
{
Type
AttributeTypeIdentifier
`json:"type"`
Value
*
string
`json:"value"`
Required
bool
`json:"required"`
Value
*
string
`json:"value
,omitempty
"`
Required
bool
`json:"required
,omitempty
"`
}
var
(
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment