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
1ac28e84
Commit
1ac28e84
authored
Feb 14, 2018
by
Koen van Ingen
Browse files
Return proofresult for each separate attribute
parent
7914f1c0
Changes
3
Hide whitespace changes
Inline
Side-by-side
attributes.go
View file @
1ac28e84
...
...
@@ -8,6 +8,7 @@ import (
"math/big"
"time"
"fmt"
"github.com/go-errors/errors"
"github.com/mhe/gabi"
)
...
...
@@ -18,6 +19,25 @@ const (
metadataLength
=
1
+
3
+
2
+
2
+
16
)
type
AttributeResultList
struct
{
AttributeResults
[]
*
AttributeResult
}
type
AttributeResult
struct
{
AttributeValue
TranslatedString
// Value of the disclosed attribute
AttributeId
AttributeTypeIdentifier
AttributeProofStatus
AttributeProofStatus
}
type
AttributeProofStatus
string
const
(
PRESENT
=
AttributeProofStatus
(
"PRESENT"
)
// Attribute is disclosed and matches the value
UNKNOWN
=
AttributeProofStatus
(
"UNKNOWN"
)
// Attribute is disclosed, but status is yet unknown
MISSING
=
AttributeProofStatus
(
"MISSING"
)
// Attribute is NOT disclosed, but should be according to request
INVALID_VALUE
=
AttributeProofStatus
(
"INVALID_VALUE"
)
// Attribute is disclosed, but has invalid value according to request
)
var
(
metadataVersion
=
[]
byte
{
0x02
}
...
...
@@ -329,7 +349,8 @@ func (disjunction *AttributeDisjunction) Satisfied() bool {
// Helper function to check if an attribute is satisfied against a list of disclosed attributes
// This is the case if:
// attribute is contained in disclosed AND if a value is present: equal to that value
func
isAttributeSatisfied
(
attribute
AttributeTypeIdentifier
,
value
string
,
disclosed
[]
*
CredentialInfo
,
conf
*
Configuration
)
bool
{
// al can be nil if you don't want to include attribute status for proof
func
isAttributeSatisfied
(
attribute
AttributeTypeIdentifier
,
value
string
,
disclosed
[]
*
CredentialInfo
,
conf
*
Configuration
,
al
*
AttributeResultList
)
bool
{
for
_
,
cred
:=
range
disclosed
{
credentialType
:=
cred
.
GetCredentialType
(
conf
)
index
,
err
:=
credentialType
.
IndexOf
(
attribute
)
...
...
@@ -340,12 +361,19 @@ func isAttributeSatisfied(attribute AttributeTypeIdentifier, value string, discl
}
disclosedAttributeValue
:=
cred
.
Attributes
[
index
]
// If it contains this attribute, check if value match (it must be disclosed (i.e. not nil) and match the value)
// Attribute is
St
ati
i
sfied if:
// If it contains this attribute, check if value match
es
(it must be disclosed (i.e. not nil) and match the value)
// Attribute is
s
atisfied if:
// - Attribute is disclosed (i.e. not nil)
// - Value is empty OR value equal to disclosedValue
if
disclosedAttributeValue
!=
nil
&&
(
value
==
""
||
disclosedAttributeValue
[
"en"
]
==
value
)
{
// TODO: fix translation/attr typing
return
true
if
disclosedAttributeValue
!=
nil
{
if
value
==
""
||
disclosedAttributeValue
[
"en"
]
==
value
{
// TODO: fix translation/attr typing
al
.
SetProofStatus
(
attribute
,
disclosedAttributeValue
,
PRESENT
)
return
true
}
else
{
// If attribute is disclosed and present, but not equal to required value, mark it as invalid_value
// We won't return true and continue searching in other disclosed attributes
al
.
SetProofStatus
(
attribute
,
disclosedAttributeValue
,
INVALID_VALUE
)
}
}
}
return
false
...
...
@@ -353,15 +381,26 @@ func isAttributeSatisfied(attribute AttributeTypeIdentifier, value string, discl
// Check whether specified attributedisjunction satisfy a list of disclosed attributes
// We return true if one of the attributes in the disjunction is satisfied
func
(
disjunction
*
AttributeDisjunction
)
SatisfyDisclosed
(
disclosed
[]
*
CredentialInfo
,
conf
*
Configuration
)
bool
{
func
(
disjunction
*
AttributeDisjunction
)
SatisfyDisclosed
(
disclosed
[]
*
CredentialInfo
,
conf
*
Configuration
,
al
*
AttributeResultList
)
bool
{
for
_
,
attr
:=
range
disjunction
.
Attributes
{
value
:=
disjunction
.
Values
[
attr
]
if
isAttributeSatisfied
(
attr
,
value
,
disclosed
,
conf
)
{
if
isAttributeSatisfied
(
attr
,
value
,
disclosed
,
conf
,
al
)
{
return
true
}
}
// Add all missing attributes
for
_
,
attr
:=
range
disjunction
.
Attributes
{
ar
:=
AttributeResult
{
AttributeId
:
attr
,
AttributeProofStatus
:
MISSING
,
}
if
!
al
.
ContainsAttributeId
(
ar
.
AttributeId
)
{
al
.
Append
(
ar
)
}
}
return
false
}
...
...
@@ -477,3 +516,87 @@ func (disjunction *AttributeDisjunction) UnmarshalJSON(bytes []byte) error {
return
nil
}
// From here attributeResult related functions. TODO: move to separate file?
func
(
al
*
AttributeResultList
)
Append
(
result
AttributeResult
)
{
al
.
AttributeResults
=
append
(
al
.
AttributeResults
,
&
result
)
}
func
(
al
*
AttributeResultList
)
ContainsAttributeId
(
attrId
AttributeTypeIdentifier
)
bool
{
for
_
,
ar
:=
range
al
.
AttributeResults
{
if
ar
.
AttributeId
==
attrId
{
return
true
}
}
return
false
}
func
(
al
*
AttributeResultList
)
String
()
string
{
// TODO: pretty print?
str
:=
"Attribute --- Value --- ProofStatus:"
for
_
,
v
:=
range
al
.
AttributeResults
{
str
=
str
+
"
\n
"
+
v
.
String
()
}
return
str
}
// Set the proof status to a new status for a specified attribute. An attribute is specified by an attributeTypeIdentifier
func
(
al
*
AttributeResultList
)
SetProofStatus
(
attrID
AttributeTypeIdentifier
,
attrValue
TranslatedString
,
status
AttributeProofStatus
)
bool
{
for
_
,
ar
:=
range
al
.
AttributeResults
{
// TODO: translation
if
ar
.
AttributeId
==
attrID
&&
ar
.
AttributeValue
[
"en"
]
==
attrValue
[
"en"
]
{
ar
.
AttributeProofStatus
=
status
return
true
}
}
return
false
}
func
(
ar
*
AttributeResult
)
GetAttributeDescription
(
conf
*
Configuration
)
(
*
AttributeDescription
,
error
)
{
cred
:=
conf
.
CredentialTypes
[
NewCredentialTypeIdentifier
(
ar
.
AttributeId
.
Parent
())]
index
,
err
:=
cred
.
IndexOf
(
ar
.
AttributeId
)
if
err
!=
nil
{
return
nil
,
err
}
return
&
cred
.
Attributes
[
index
],
nil
}
func
(
ar
*
AttributeResult
)
String
()
string
{
// TODO: translated string!
return
fmt
.
Sprintf
(
"%v --- %v --- %v"
,
ar
.
AttributeId
,
ar
.
AttributeValue
[
"en"
],
ar
.
AttributeProofStatus
)
}
func
AttributeResultListFromDisclosed
(
disclosed
[]
*
CredentialInfo
,
conf
*
Configuration
)
*
AttributeResultList
{
al
:=
AttributeResultList
{}
for
_
,
cred
:=
range
disclosed
{
credentialType
:=
cred
.
GetCredentialType
(
conf
)
for
_
,
attr
:=
range
credentialType
.
Attributes
{
attrId
:=
NewAttributeTypeIdentifier
(
cred
.
CredentialTypeID
.
String
()
+
"."
+
attr
.
ID
)
index
,
err
:=
credentialType
.
IndexOf
(
attrId
)
if
err
!=
nil
{
// Specified credential does not contain this attribute, move to next
break
}
disclosedAttributeValue
:=
cred
.
Attributes
[
index
]
if
disclosedAttributeValue
!=
nil
{
al
.
Append
(
AttributeResult
{
AttributeValue
:
disclosedAttributeValue
,
AttributeId
:
attrId
,
AttributeProofStatus
:
UNKNOWN
,
})
}
}
}
return
&
al
}
irmaclient/manual_session_test.go
View file @
1ac28e84
...
...
@@ -10,12 +10,17 @@ import (
"testing"
)
type
Result
struct
{
proofStatus
ProofStatus
attributes
*
irma
.
AttributeResultList
}
type
ManualSessionHandler
struct
{
permissionHandler
PermissionHandler
pinHandler
PinHandler
t
*
testing
.
T
errorChannel
chan
*
irma
.
SessionError
resultChannel
chan
ProofStatus
resultChannel
chan
Result
sigRequest
*
irma
.
SignatureRequest
// Request used to create signature
sigVerifyRequest
*
irma
.
SignatureRequest
// Request used to verify signature
}
...
...
@@ -51,7 +56,7 @@ func corruptProofString(proof string) string {
// Create a ManualSessionHandler for unit tests
func
createManualSessionHandler
(
request
string
,
invalidRequest
string
,
t
*
testing
.
T
)
ManualSessionHandler
{
errorChannel
:=
make
(
chan
*
irma
.
SessionError
)
resultChannel
:=
make
(
chan
ProofStatus
)
resultChannel
:=
make
(
chan
Result
)
sigRequestJSON
:=
[]
byte
(
request
)
invalidSigRequestJSON
:=
[]
byte
(
invalidRequest
)
...
...
@@ -84,8 +89,13 @@ func TestManualSession(t *testing.T) {
}
// No errors, obtain proof result from channel
if
result
:=
<-
ms
.
resultChannel
;
result
!=
VALID
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
,
VALID
)
result
:=
<-
ms
.
resultChannel
if
ps
:=
result
.
proofStatus
;
ps
!=
VALID
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
ps
,
VALID
)
t
.
Fail
()
}
if
attrStatus
:=
result
.
attributes
.
AttributeResults
[
0
]
.
AttributeProofStatus
;
attrStatus
!=
irma
.
PRESENT
{
t
.
Logf
(
"Invalid attribute result value: %v Expected: %v"
,
attrStatus
,
irma
.
PRESENT
)
t
.
Fail
()
}
test
.
ClearTestStorage
(
t
)
...
...
@@ -127,8 +137,8 @@ func TestManualSessionInvalidNonce(t *testing.T) {
}
// No errors, obtain proof result from channel
if
result
:=
<-
ms
.
resultChannel
;
result
!=
INVALID_CRYPTO
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
,
INVALID_CRYPTO
)
if
result
:=
<-
ms
.
resultChannel
;
result
.
proofStatus
!=
INVALID_CRYPTO
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
.
proofStatus
,
INVALID_CRYPTO
)
t
.
Fail
()
}
test
.
ClearTestStorage
(
t
)
...
...
@@ -152,8 +162,19 @@ func TestManualSessionInvalidRequest(t *testing.T) {
}
// No errors, obtain proof result from channel
if
result
:=
<-
ms
.
resultChannel
;
result
!=
MISSING_ATTRIBUTES
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
,
MISSING_ATTRIBUTES
)
result
:=
<-
ms
.
resultChannel
if
ps
:=
result
.
proofStatus
;
ps
!=
MISSING_ATTRIBUTES
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
ps
,
MISSING_ATTRIBUTES
)
t
.
Fail
()
}
// First attribute result is UNKOWN, since it is disclosed, but not matching the sigrequest
if
attrStatus
:=
result
.
attributes
.
AttributeResults
[
0
]
.
AttributeProofStatus
;
attrStatus
!=
irma
.
UNKNOWN
{
t
.
Logf
(
"Invalid attribute result value: %v Expected: %v"
,
attrStatus
,
irma
.
UNKNOWN
)
t
.
Fail
()
}
// Second attribute result is MISSING, because it is in the request but not disclosed
if
attrStatus
:=
result
.
attributes
.
AttributeResults
[
1
]
.
AttributeProofStatus
;
attrStatus
!=
irma
.
MISSING
{
t
.
Logf
(
"Invalid attribute result value: %v Expected: %v"
,
attrStatus
,
irma
.
MISSING
)
t
.
Fail
()
}
test
.
ClearTestStorage
(
t
)
...
...
@@ -177,8 +198,13 @@ func TestManualSessionInvalidAttributeValue(t *testing.T) {
}
// No errors, obtain proof result from channel
if
result
:=
<-
ms
.
resultChannel
;
result
!=
MISSING_ATTRIBUTES
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
,
MISSING_ATTRIBUTES
)
result
:=
<-
ms
.
resultChannel
if
ps
:=
result
.
proofStatus
;
ps
!=
MISSING_ATTRIBUTES
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
ps
,
MISSING_ATTRIBUTES
)
t
.
Fail
()
}
if
attrStatus
:=
result
.
attributes
.
AttributeResults
[
0
]
.
AttributeProofStatus
;
attrStatus
!=
irma
.
INVALID_VALUE
{
t
.
Logf
(
"Invalid attribute result value: %v Expected: %v"
,
attrStatus
,
irma
.
INVALID_VALUE
)
t
.
Fail
()
}
test
.
ClearTestStorage
(
t
)
...
...
@@ -200,8 +226,8 @@ func TestManualKeyShareSession(t *testing.T) {
}
// No errors, obtain proof result from channel
if
result
:=
<-
ms
.
resultChannel
;
result
!=
VALID
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
,
VALID
)
if
result
:=
<-
ms
.
resultChannel
;
result
.
proofStatus
!=
VALID
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
.
proofStatus
,
VALID
)
t
.
Fail
()
}
test
.
ClearTestStorage
(
t
)
...
...
@@ -232,8 +258,8 @@ func TestManualSessionMultiProof(t *testing.T) {
}
// No errors, obtain proof result from channel
if
result
:=
<-
ms
.
resultChannel
;
result
!=
VALID
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
,
VALID
)
if
result
:=
<-
ms
.
resultChannel
;
result
.
proofStatus
!=
VALID
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
.
proofStatus
,
VALID
)
t
.
Fail
()
}
test
.
ClearTestStorage
(
t
)
...
...
@@ -254,8 +280,8 @@ func TestManualSessionInvalidProof(t *testing.T) {
}
// No errors, obtain proof result from channel
if
result
:=
<-
ms
.
resultChannel
;
result
!=
INVALID_CRYPTO
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
,
INVALID_CRYPTO
)
if
result
:=
<-
ms
.
resultChannel
;
result
.
proofStatus
!=
INVALID_CRYPTO
{
t
.
Logf
(
"Invalid proof result: %v Expected: %v"
,
result
.
proofStatus
,
INVALID_CRYPTO
)
t
.
Fail
()
}
test
.
ClearTestStorage
(
t
)
...
...
@@ -268,7 +294,8 @@ func (sh *ManualSessionHandler) Success(irmaAction irma.Action, result string) {
result
=
corruptProofString
(
result
)
go
func
()
{
sh
.
resultChannel
<-
VerifySig
(
client
.
Configuration
,
result
,
sh
.
sigVerifyRequest
)
proofStatus
,
attributeResultList
:=
VerifySig
(
client
.
Configuration
,
result
,
sh
.
sigVerifyRequest
)
sh
.
resultChannel
<-
Result
{
proofStatus
,
attributeResultList
}
}()
}
sh
.
errorChannel
<-
nil
...
...
irmaclient/verify.go
View file @
1ac28e84
...
...
@@ -8,6 +8,12 @@ import (
"math/big"
)
// TODO: move to irma package?
type
ProofResult
struct
{
proofStatus
ProofStatus
// The overall proofstatus, should be VALID in order to accept the proof
attributes
[]
irma
.
AttributeResult
}
type
ProofStatus
string
const
(
...
...
@@ -58,28 +64,29 @@ func extractDisclosedCredentials(configuration *irma.Configuration, proofList *g
return
credentials
,
nil
}
func
checkProofWithRequest
(
configuration
*
irma
.
Configuration
,
proofList
*
gabi
.
ProofList
,
sigRequest
*
irma
.
SignatureRequest
)
ProofStatus
{
func
checkProofWithRequest
(
configuration
*
irma
.
Configuration
,
proofList
*
gabi
.
ProofList
,
sigRequest
*
irma
.
SignatureRequest
)
(
ProofStatus
,
*
irma
.
AttributeResultList
)
{
credentials
,
err
:=
extractDisclosedCredentials
(
configuration
,
proofList
)
if
err
!=
nil
{
fmt
.
Println
(
err
)
return
INVALID_CRYPTO
return
INVALID_CRYPTO
,
nil
}
al
:=
irma
.
AttributeResultListFromDisclosed
(
credentials
,
configuration
)
for
_
,
content
:=
range
sigRequest
.
Content
{
if
!
content
.
SatisfyDisclosed
(
credentials
,
configuration
)
{
return
MISSING_ATTRIBUTES
if
!
content
.
SatisfyDisclosed
(
credentials
,
configuration
,
al
)
{
return
MISSING_ATTRIBUTES
,
al
}
}
// Check if a credential is expired
for
_
,
cred
:=
range
credentials
{
if
cred
.
IsExpired
()
{
return
EXPIRED
return
EXPIRED
,
al
}
}
return
VALID
return
VALID
,
al
}
// Verify an IRMA proof cryptographically
...
...
@@ -95,7 +102,7 @@ func verify(configuration *irma.Configuration, proofList *gabi.ProofList, contex
}
// Verify a signature proof and check if the attributes match the attributes in the original request
func
VerifySig
(
configuration
*
irma
.
Configuration
,
proofString
string
,
sigRequest
*
irma
.
SignatureRequest
)
ProofStatus
{
func
VerifySig
(
configuration
*
irma
.
Configuration
,
proofString
string
,
sigRequest
*
irma
.
SignatureRequest
)
(
ProofStatus
,
*
irma
.
AttributeResultList
)
{
// First, unmarshal proof and check if all the attributes in the proofstring match the signature request
var
proofList
gabi
.
ProofList
...
...
@@ -104,12 +111,12 @@ func VerifySig(configuration *irma.Configuration, proofString string, sigRequest
err
:=
proofList
.
UnmarshalJSON
(
proofBytes
)
if
err
!=
nil
{
fmt
.
Printf
(
"Error unmarshalling JSON: %v
\n
"
,
err
)
return
INVALID_JSON
return
INVALID_JSON
,
nil
}
// Now, cryptographically verify the signature
if
!
verify
(
configuration
,
&
proofList
,
sigRequest
.
GetContext
(),
sigRequest
.
GetNonce
(),
true
)
{
return
INVALID_CRYPTO
return
INVALID_CRYPTO
,
nil
}
// Finally, check whether attribute values in proof satisfy the original signature request
...
...
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