Skip to content
GitLab
Menu
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
903aa88c
Commit
903aa88c
authored
Aug 05, 2018
by
Sietse Ringers
Browse files
Support manual disclosure sessions
parent
1fc0ae14
Changes
4
Hide whitespace changes
Inline
Side-by-side
irmaclient/handlers_test.go
View file @
903aa88c
...
...
@@ -4,6 +4,7 @@ import (
"encoding/json"
"testing"
"github.com/mhe/gabi"
"github.com/pkg/errors"
"github.com/privacybydesign/irmago"
)
...
...
@@ -128,14 +129,20 @@ func (th TestHandler) RequestPin(remainingAttempts int, callback PinHandler) {
}
type
SessionResult
struct
{
Err
error
Result
*
irma
.
SignedMessage
Err
error
SignatureResult
*
irma
.
SignedMessage
VerificationResult
gabi
.
ProofList
}
// ManualTestHandler embeds a TestHandler to inherit its methods.
// Below we overwrite the methods that require behaviour specific to manual settings.
type
ManualTestHandler
struct
{
TestHandler
action
irma
.
Action
}
func
(
th
*
ManualTestHandler
)
StatusUpdate
(
action
irma
.
Action
,
status
irma
.
Status
)
{
th
.
action
=
action
}
func
(
th
*
ManualTestHandler
)
Success
(
result
string
)
{
...
...
@@ -143,9 +150,22 @@ func (th *ManualTestHandler) Success(result string) {
th
.
c
<-
nil
return
}
irmaSignedMessage
:=
&
irma
.
SignedMessage
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
result
),
irmaSignedMessage
);
err
!=
nil
{
var
err
error
retval
:=
&
SessionResult
{}
switch
th
.
action
{
case
irma
.
ActionSigning
:
retval
.
SignatureResult
=
&
irma
.
SignedMessage
{}
err
=
json
.
Unmarshal
([]
byte
(
result
),
retval
.
SignatureResult
)
case
irma
.
ActionDisclosing
:
proofs
:=
[]
*
gabi
.
ProofD
{}
err
=
json
.
Unmarshal
([]
byte
(
result
),
&
proofs
)
retval
.
VerificationResult
=
make
(
gabi
.
ProofList
,
len
(
proofs
))
for
i
,
proof
:=
range
proofs
{
retval
.
VerificationResult
[
i
]
=
proof
}
}
if
err
!=
nil
{
th
.
Failure
(
&
irma
.
SessionError
{
Err
:
err
,
ErrorType
:
irma
.
ErrorSerialization
,
...
...
@@ -153,17 +173,10 @@ func (th *ManualTestHandler) Success(result string) {
return
}
th
.
c
<-
&
SessionResult
{
Result
:
irmaSignedMessage
,
}
th
.
c
<-
retval
}
func
(
th
*
ManualTestHandler
)
RequestSignaturePermission
(
request
irma
.
SignatureRequest
,
requesterName
string
,
ph
PermissionHandler
)
{
var
attributes
[]
*
irma
.
AttributeIdentifier
for
_
,
cand
:=
range
request
.
Candidates
{
attributes
=
append
(
attributes
,
cand
[
0
])
}
c
:=
irma
.
DisclosureChoice
{
attributes
}
ph
(
true
,
&
c
)
th
.
RequestVerificationPermission
(
request
.
DisclosureRequest
,
requesterName
,
ph
)
}
func
(
th
*
ManualTestHandler
)
RequestIssuancePermission
(
request
irma
.
IssuanceRequest
,
issuerName
string
,
ph
PermissionHandler
)
{
ph
(
true
,
nil
)
...
...
@@ -174,5 +187,10 @@ func (th *ManualTestHandler) RequestSchemeManagerPermission(manager *irma.Scheme
th
.
Failure
(
&
irma
.
SessionError
{
Err
:
errors
.
New
(
"Unexpected session type"
)})
}
func
(
th
*
ManualTestHandler
)
RequestVerificationPermission
(
request
irma
.
DisclosureRequest
,
verifierName
string
,
ph
PermissionHandler
)
{
th
.
Failure
(
&
irma
.
SessionError
{
Err
:
errors
.
New
(
"Unexpected session type"
)})
var
attributes
[]
*
irma
.
AttributeIdentifier
for
_
,
cand
:=
range
request
.
Candidates
{
attributes
=
append
(
attributes
,
cand
[
0
])
}
c
:=
irma
.
DisclosureChoice
{
attributes
}
ph
(
true
,
&
c
)
}
irmaclient/manual_session_test.go
View file @
903aa88c
...
...
@@ -35,19 +35,29 @@ func manualSessionHelper(t *testing.T, client *Client, h *ManualTestHandler, req
require
.
NoError
(
t
,
result
.
Err
)
}
var
verifyasRequest
*
irma
.
SignatureRequest
if
verifyAs
!=
""
{
verifyasRequest
=
&
irma
.
Signat
ureRequest
{}
switch
h
.
action
{
case
irma
.
ActionDisclosing
:
verifyasRequest
:
=
&
irma
.
Disclos
ureRequest
{}
err
:=
json
.
Unmarshal
([]
byte
(
verifyAs
),
verifyasRequest
)
require
.
NoError
(
t
,
err
)
return
irma
.
ProofList
(
result
.
VerificationResult
)
.
Verify
(
client
.
Configuration
,
verifyasRequest
)
case
irma
.
ActionSigning
:
var
verifyasRequest
*
irma
.
SignatureRequest
if
verifyAs
!=
""
{
verifyasRequest
=
&
irma
.
SignatureRequest
{}
err
:=
json
.
Unmarshal
([]
byte
(
verifyAs
),
verifyasRequest
)
require
.
NoError
(
t
,
err
)
}
if
corrupt
{
// Interesting: modifying C results in INVALID_CRYPTO; modifying A or an attribute results in INVALID_TIMESTAMP
i
:=
result
.
SignatureResult
.
Signature
[
0
]
.
(
*
gabi
.
ProofD
)
.
C
i
.
Add
(
i
,
big
.
NewInt
(
16
))
}
return
result
.
SignatureResult
.
Verify
(
client
.
Configuration
,
verifyasRequest
)
default
:
return
nil
}
if
corrupt
{
// Interesting: modifying C results in INVALID_CRYPTO; modifying A or an attribute results in INVALID_TIMESTAMP
i
:=
result
.
Result
.
Signature
[
0
]
.
(
*
gabi
.
ProofD
)
.
C
i
.
Add
(
i
,
big
.
NewInt
(
16
))
}
return
result
.
Result
.
Verify
(
client
.
Configuration
,
verifyasRequest
)
}
func
TestManualSession
(
t
*
testing
.
T
)
{
...
...
@@ -153,3 +163,31 @@ func TestManualSessionInvalidProof(t *testing.T) {
test
.
ClearTestStorage
(
t
)
}
func
TestManualDisclosureSession
(
t
*
testing
.
T
)
{
request
:=
"{
\"
nonce
\"
: 0,
\"
context
\"
: 0,
\"
type
\"
:
\"
disclosing
\"
,
\"
content
\"
:[{
\"
label
\"
:
\"
Student number (RU)
\"
,
\"
attributes
\"
:[
\"
irma-demo.RU.studentCard.studentID
\"
]}]}"
ms
:=
createManualSessionHandler
(
t
,
nil
)
result
:=
manualSessionHelper
(
t
,
nil
,
ms
,
request
,
request
,
false
)
require
.
Equal
(
t
,
irma
.
AttributeProofStatusPresent
,
result
.
Attributes
[
0
]
.
Status
)
require
.
Equal
(
t
,
"456"
,
result
.
Attributes
[
0
]
.
Value
[
"en"
])
require
.
Equal
(
t
,
irma
.
ProofStatusValid
,
result
.
Status
)
test
.
ClearTestStorage
(
t
)
}
// Test if proof verification fails with status 'MISSING_ATTRIBUTES' if we provide it with a non-matching disclosure request
func
TestManualDisclosureSessionInvalidRequest
(
t
*
testing
.
T
)
{
request
:=
"{
\"
nonce
\"
: 0,
\"
context
\"
: 0,
\"
type
\"
:
\"
disclosing
\"
,
\"
content
\"
:[{
\"
label
\"
:
\"
Student number (RU)
\"
,
\"
attributes
\"
:[
\"
irma-demo.RU.studentCard.studentID
\"
]}]}"
invalidRequest
:=
"{
\"
nonce
\"
: 0,
\"
context
\"
: 0,
\"
type
\"
:
\"
disclosing
\"
,
\"
content
\"
:[{
\"
label
\"
:
\"
Student number (RU)
\"
,
\"
attributes
\"
:[
\"
irma-demo.RU.studentCard.university
\"
]}]}"
ms
:=
createManualSessionHandler
(
t
,
nil
)
result
:=
manualSessionHelper
(
t
,
nil
,
ms
,
request
,
invalidRequest
,
false
)
require
.
Equal
(
t
,
irma
.
ProofStatusMissingAttributes
,
result
.
Status
)
// First attribute result is MISSING, because it is in the request but not disclosed
require
.
Equal
(
t
,
irma
.
AttributeProofStatusMissing
,
result
.
Attributes
[
0
]
.
Status
)
// Second attribute result is EXTRA, since it is disclosed, but not matching the sigrequest
require
.
Equal
(
t
,
irma
.
AttributeProofStatusExtra
,
result
.
Attributes
[
1
]
.
Status
)
test
.
ClearTestStorage
(
t
)
}
irmaclient/session.go
View file @
903aa88c
...
...
@@ -104,7 +104,12 @@ func (client *Client) NewSession(sessionrequest string, handler Handler) Session
sigRequest
:=
&
irma
.
SignatureRequest
{}
if
err
:=
irma
.
UnmarshalValidate
(
bts
,
sigRequest
);
err
==
nil
{
return
client
.
newManualSession
(
sigRequest
,
handler
)
return
client
.
newManualSession
(
sigRequest
,
handler
,
irma
.
ActionSigning
)
}
disclosureRequest
:=
&
irma
.
DisclosureRequest
{}
if
err
:=
irma
.
UnmarshalValidate
(
bts
,
disclosureRequest
);
err
==
nil
{
return
client
.
newManualSession
(
disclosureRequest
,
handler
,
irma
.
ActionDisclosing
)
}
handler
.
Failure
(
&
irma
.
SessionError
{
Err
:
errors
.
New
(
"Session request could not be parsed"
)})
...
...
@@ -112,14 +117,14 @@ func (client *Client) NewSession(sessionrequest string, handler Handler) Session
}
// newManualSession starts a manual session, given a signature request in JSON and a handler to pass messages to
func
(
client
*
Client
)
newManualSession
(
sig
request
*
irma
.
S
ignature
Request
,
handler
Handler
)
SessionDismisser
{
func
(
client
*
Client
)
newManualSession
(
request
irma
.
S
ession
Request
,
handler
Handler
,
action
irma
.
Action
)
SessionDismisser
{
session
:=
&
session
{
Action
:
irma
.
ActionSigning
,
// TODO hardcoded for now
Action
:
action
,
Handler
:
handler
,
client
:
client
,
Version
:
minVersion
,
ServerName
:
"
Email request
"
,
request
:
sig
request
,
ServerName
:
""
,
request
:
request
,
}
session
.
Handler
.
StatusUpdate
(
session
.
Action
,
irma
.
StatusManualStarted
)
...
...
@@ -308,13 +313,7 @@ func (session *session) sendResponse(message interface{}) {
switch
session
.
Action
{
case
irma
.
ActionSigning
:
request
,
ok
:=
session
.
request
.
(
*
irma
.
SignatureRequest
)
if
!
ok
{
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorSerialization
,
Info
:
"Type assertion failed"
})
return
}
irmaSignature
,
err
:=
request
.
SignatureFromMessage
(
message
)
irmaSignature
,
err
:=
session
.
request
.
(
*
irma
.
SignatureRequest
)
.
SignatureFromMessage
(
message
)
if
err
!=
nil
{
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorSerialization
,
Info
:
"Type assertion failed"
})
return
...
...
@@ -339,14 +338,21 @@ func (session *session) sendResponse(message interface{}) {
}
log
,
_
=
session
.
createLogEntry
(
message
.
(
gabi
.
ProofList
))
// TODO err
case
irma
.
ActionDisclosing
:
var
response
disclosureResponse
if
err
=
session
.
transport
.
Post
(
"proofs"
,
&
response
,
message
);
err
!=
nil
{
session
.
fail
(
err
.
(
*
irma
.
SessionError
)
)
messageJson
,
err
=
json
.
Marshal
(
message
)
if
err
!=
nil
{
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorSerialization
,
Err
:
err
}
)
return
}
if
response
!=
"VALID"
{
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorRejected
,
Info
:
string
(
response
)})
return
if
session
.
IsInteractive
()
{
var
response
disclosureResponse
if
err
=
session
.
transport
.
Post
(
"proofs"
,
&
response
,
message
);
err
!=
nil
{
session
.
fail
(
err
.
(
*
irma
.
SessionError
))
return
}
if
response
!=
"VALID"
{
session
.
fail
(
&
irma
.
SessionError
{
ErrorType
:
irma
.
ErrorRejected
,
Info
:
string
(
response
)})
return
}
}
log
,
_
=
session
.
createLogEntry
(
message
.
(
gabi
.
ProofList
))
// TODO err
case
irma
.
ActionIssuing
:
...
...
verify.go
View file @
903aa88c
...
...
@@ -70,8 +70,8 @@ func (pl ProofList) extractPublicKeys(configuration *Configuration) ([]*gabi.Pub
return
publicKeys
,
nil
}
// Verify the proofs cryptographically.
func
(
pl
ProofList
)
Verify
(
configuration
*
Configuration
,
context
*
big
.
Int
,
nonce
*
big
.
Int
,
isSig
bool
)
bool
{
// Verify
Proofs verifies
the proofs cryptographically.
func
(
pl
ProofList
)
Verify
Proofs
(
configuration
*
Configuration
,
context
*
big
.
Int
,
nonce
*
big
.
Int
,
isSig
bool
)
bool
{
// Extract public keys
pks
,
err
:=
pl
.
extractPublicKeys
(
configuration
)
if
err
!=
nil
{
...
...
@@ -172,6 +172,35 @@ func (pl ProofList) DisclosedAttributes(configuration *Configuration, disjunctio
return
len
(
disjunctions
)
==
0
||
disjunctions
.
satisfied
(),
list
,
nil
}
func
(
pl
ProofList
)
verifyAgainstDisjunctions
(
configuration
*
Configuration
,
required
AttributeDisjunctionList
,
nonce
,
context
*
big
.
Int
,
issig
bool
)
([]
*
DisclosedAttribute
,
ProofStatus
)
{
// Cryptographically verify the IRMA disclosure proofs in the signature
if
!
pl
.
VerifyProofs
(
configuration
,
nonce
,
context
,
issig
)
{
return
nil
,
ProofStatusInvalidCrypto
}
// Next extract the contained attributes from the proofs, and match them to the signature request if present
allmatched
,
list
,
err
:=
pl
.
DisclosedAttributes
(
configuration
,
required
)
if
err
!=
nil
{
return
nil
,
ProofStatusInvalidCrypto
}
// Return MISSING_ATTRIBUTES as proofstatus if one of the disjunctions in the request (if present) is not satisfied
// This status takes priority over 'EXPIRED'
if
!
allmatched
{
return
list
,
ProofStatusMissingAttributes
}
return
list
,
ProofStatusValid
}
func
(
pl
ProofList
)
Verify
(
configuration
*
Configuration
,
request
*
DisclosureRequest
)
*
VerificationResult
{
list
,
status
:=
pl
.
verifyAgainstDisjunctions
(
configuration
,
request
.
Content
,
request
.
Nonce
,
request
.
Context
,
false
)
return
&
VerificationResult
{
Attributes
:
list
,
Status
:
status
,
}
}
// Verify the attribute-based signature, optionally against a corresponding signature request. If the request is present
// (i.e. not nil), then the first attributes in the returned result match with the disjunction list in the request
// (that is, the i'th attribute in the result should satisfy the i'th disjunction in the request). If the request is not
...
...
@@ -208,29 +237,13 @@ func (sm *SignedMessage) Verify(configuration *Configuration, request *Signature
}
// Now, cryptographically verify the IRMA disclosure proofs in the signature
proofList
:=
ProofList
(
sm
.
Signature
)
if
!
proofList
.
Verify
(
configuration
,
sm
.
Context
,
sm
.
GetNonce
(),
true
)
{
result
.
Status
=
ProofStatusInvalidCrypto
return
}
// Next extract the contained attributes from the signature, and match them to the signature request if present
var
allmatched
bool
var
err
error
var
disjunctions
AttributeDisjunctionList
pl
:=
ProofList
(
sm
.
Signature
)
var
required
AttributeDisjunctionList
if
request
!=
nil
{
disjunctions
=
request
.
Content
required
=
request
.
Content
}
allmatched
,
result
.
Attributes
,
err
=
proofList
.
DisclosedAttributes
(
configuration
,
disjunctions
)
if
err
!=
nil
{
result
.
Status
=
ProofStatusInvalidCrypto
return
}
// Return MISSING_ATTRIBUTES as proofstatus if one of the disjunctions in the request (if present) is not satisfied
// This status takes priority over 'EXPIRED'
if
!
allmatched
{
result
.
Status
=
ProofStatusMissingAttributes
result
.
Attributes
,
result
.
Status
=
pl
.
verifyAgainstDisjunctions
(
configuration
,
required
,
sm
.
Context
,
sm
.
GetNonce
(),
true
)
if
result
.
Status
!=
ProofStatusValid
{
return
}
...
...
@@ -239,7 +252,7 @@ func (sm *SignedMessage) Verify(configuration *Configuration, request *Signature
if
sm
.
Timestamp
!=
nil
{
t
=
time
.
Unix
(
sm
.
Timestamp
.
Time
,
0
)
}
expired
,
err
:=
p
roofList
.
Expired
(
configuration
,
&
t
)
expired
,
err
:=
p
l
.
Expired
(
configuration
,
&
t
)
if
err
!=
nil
{
result
.
Status
=
ProofStatusInvalidCrypto
return
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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